
; var __LiteMol_Plugin = function () {
  'use strict';
/*!
 * @overview es6-promise - a tiny implementation of Promises/A+.
 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
 * @version   3.2.1
 */

var __createPromise = function (__promise) {
    "use strict";
    function lib$es6$promise$utils$$objectOrFunction(x) {
        return typeof x === 'function' || (typeof x === 'object' && x !== null);
    }

    function lib$es6$promise$utils$$isFunction(x) {
        return typeof x === 'function';
    }

    function lib$es6$promise$utils$$isMaybeThenable(x) {
        return typeof x === 'object' && x !== null;
    }

    var lib$es6$promise$utils$$_isArray;
    if (!Array.isArray) {
        lib$es6$promise$utils$$_isArray = function (x) {
            return Object.prototype.toString.call(x) === '[object Array]';
        };
    } else {
        lib$es6$promise$utils$$_isArray = Array.isArray;
    }

    var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray;
    var lib$es6$promise$asap$$len = 0;
    var lib$es6$promise$asap$$vertxNext;
    var lib$es6$promise$asap$$customSchedulerFn;

    var lib$es6$promise$asap$$asap = function asap(callback, arg) {
        lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback;
        lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg;
        lib$es6$promise$asap$$len += 2;
        if (lib$es6$promise$asap$$len === 2) {
            // If len is 2, that means that we need to schedule an async flush.
            // If additional callbacks are queued before the queue is flushed, they
            // will be processed by this flush that we are scheduling.
            if (lib$es6$promise$asap$$customSchedulerFn) {
                lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush);
            } else {
                lib$es6$promise$asap$$scheduleFlush();
            }
        }
    }

    function lib$es6$promise$asap$$setScheduler(scheduleFn) {
        lib$es6$promise$asap$$customSchedulerFn = scheduleFn;
    }

    function lib$es6$promise$asap$$setAsap(asapFn) {
        lib$es6$promise$asap$$asap = asapFn;
    }

    var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
    var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {};
    var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;
    var lib$es6$promise$asap$$isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';

    // test for web worker but not in IE10
    var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
      typeof importScripts !== 'undefined' &&
      typeof MessageChannel !== 'undefined';

    // node
    function lib$es6$promise$asap$$useNextTick() {
        // node version 0.10.x displays a deprecation warning when nextTick is used recursively
        // see https://github.com/cujojs/when/issues/410 for details
        return function () {
            process.nextTick(lib$es6$promise$asap$$flush);
        };
    }

    // vertx
    function lib$es6$promise$asap$$useVertxTimer() {
        return function () {
            lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush);
        };
    }

    function lib$es6$promise$asap$$useMutationObserver() {
        var iterations = 0;
        var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);
        var node = document.createTextNode('');
        observer.observe(node, { characterData: true });

        return function () {
            node.data = (iterations = ++iterations % 2);
        };
    }

    // web worker
    function lib$es6$promise$asap$$useMessageChannel() {
        var channel = new MessageChannel();
        channel.port1.onmessage = lib$es6$promise$asap$$flush;
        return function () {
            channel.port2.postMessage(0);
        };
    }

    function lib$es6$promise$asap$$useSetTimeout() {
        return function () {
            setTimeout(lib$es6$promise$asap$$flush, 1);
        };
    }

    var lib$es6$promise$asap$$queue = new Array(1000);
    function lib$es6$promise$asap$$flush() {
        for (var i = 0; i < lib$es6$promise$asap$$len; i += 2) {
            var callback = lib$es6$promise$asap$$queue[i];
            var arg = lib$es6$promise$asap$$queue[i + 1];

            callback(arg);

            lib$es6$promise$asap$$queue[i] = undefined;
            lib$es6$promise$asap$$queue[i + 1] = undefined;
        }

        lib$es6$promise$asap$$len = 0;
    }

    ////function lib$es6$promise$asap$$attemptVertx() {
    ////    try {
    ////        var r = require;
    ////        var vertx = r('vertx');
    ////        lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
    ////        return lib$es6$promise$asap$$useVertxTimer();
    ////    } catch (e) {
    ////        return lib$es6$promise$asap$$useSetTimeout();
    ////    }
    ////}

    var lib$es6$promise$asap$$scheduleFlush;
    // Decide what async method to use to triggering processing of queued callbacks:
    if (lib$es6$promise$asap$$isNode) {
        lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick();
    } else if (lib$es6$promise$asap$$BrowserMutationObserver) {
        lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver();
    } else if (lib$es6$promise$asap$$isWorker) {
        lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel();
    } /*else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') {
        lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertx();
    }*/ else {
        lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout();
    }
    function lib$es6$promise$then$$then(onFulfillment, onRejection) {
        var parent = this;

        var child = new this.constructor(lib$es6$promise$$internal$$noop);

        if (child[lib$es6$promise$$internal$$PROMISE_ID] === undefined) {
            lib$es6$promise$$internal$$makePromise(child);
        }

        var state = parent._state;

        if (state) {
            var callback = arguments[state - 1];
            lib$es6$promise$asap$$asap(function () {
                lib$es6$promise$$internal$$invokeCallback(state, child, callback, parent._result);
            });
        } else {
            lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);
        }

        return child;
    }
    var lib$es6$promise$then$$default = lib$es6$promise$then$$then;
    function lib$es6$promise$promise$resolve$$resolve(object) {
        /*jshint validthis:true */
        var Constructor = this;

        if (object && typeof object === 'object' && object.constructor === Constructor) {
            return object;
        }

        var promise = new Constructor(lib$es6$promise$$internal$$noop);
        lib$es6$promise$$internal$$resolve(promise, object);
        return promise;
    }
    var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve;
    var lib$es6$promise$$internal$$PROMISE_ID = Math.random().toString(36).substring(16);

    function lib$es6$promise$$internal$$noop() { }

    var lib$es6$promise$$internal$$PENDING = void 0;
    var lib$es6$promise$$internal$$FULFILLED = 1;
    var lib$es6$promise$$internal$$REJECTED = 2;

    var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject();

    function lib$es6$promise$$internal$$selfFulfillment() {
        return new TypeError("You cannot resolve a promise with itself");
    }

    function lib$es6$promise$$internal$$cannotReturnOwn() {
        return new TypeError('A promises callback cannot return that same promise.');
    }

    function lib$es6$promise$$internal$$getThen(promise) {
        try {
            return promise.then;
        } catch (error) {
            lib$es6$promise$$internal$$GET_THEN_ERROR.error = error;
            return lib$es6$promise$$internal$$GET_THEN_ERROR;
        }
    }

    function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
        try {
            then.call(value, fulfillmentHandler, rejectionHandler);
        } catch (e) {
            return e;
        }
    }

    function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) {
        lib$es6$promise$asap$$asap(function (promise) {
            var sealed = false;
            var error = lib$es6$promise$$internal$$tryThen(then, thenable, function (value) {
                if (sealed) { return; }
                sealed = true;
                if (thenable !== value) {
                    lib$es6$promise$$internal$$resolve(promise, value);
                } else {
                    lib$es6$promise$$internal$$fulfill(promise, value);
                }
            }, function (reason) {
                if (sealed) { return; }
                sealed = true;

                lib$es6$promise$$internal$$reject(promise, reason);
            }, 'Settle: ' + (promise._label || ' unknown promise'));

            if (!sealed && error) {
                sealed = true;
                lib$es6$promise$$internal$$reject(promise, error);
            }
        }, promise);
    }

    function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) {
        if (thenable._state === lib$es6$promise$$internal$$FULFILLED) {
            lib$es6$promise$$internal$$fulfill(promise, thenable._result);
        } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) {
            lib$es6$promise$$internal$$reject(promise, thenable._result);
        } else {
            lib$es6$promise$$internal$$subscribe(thenable, undefined, function (value) {
                lib$es6$promise$$internal$$resolve(promise, value);
            }, function (reason) {
                lib$es6$promise$$internal$$reject(promise, reason);
            });
        }
    }

    function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable, then) {
        if (maybeThenable.constructor === promise.constructor &&
            then === lib$es6$promise$then$$default &&
            constructor.resolve === lib$es6$promise$promise$resolve$$default) {
            lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable);
        } else {
            if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) {
                lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error);
            } else if (then === undefined) {
                lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
            } else if (lib$es6$promise$utils$$isFunction(then)) {
                lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then);
            } else {
                lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
            }
        }
    }

    function lib$es6$promise$$internal$$resolve(promise, value) {
        if (promise === value) {
            lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFulfillment());
        } else if (lib$es6$promise$utils$$objectOrFunction(value)) {
            lib$es6$promise$$internal$$handleMaybeThenable(promise, value, lib$es6$promise$$internal$$getThen(value));
        } else {
            lib$es6$promise$$internal$$fulfill(promise, value);
        }
    }

    function lib$es6$promise$$internal$$publishRejection(promise) {
        if (promise._onerror) {
            promise._onerror(promise._result);
        }

        lib$es6$promise$$internal$$publish(promise);
    }

    function lib$es6$promise$$internal$$fulfill(promise, value) {
        if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }

        promise._result = value;
        promise._state = lib$es6$promise$$internal$$FULFILLED;

        if (promise._subscribers.length !== 0) {
            lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise);
        }
    }

    function lib$es6$promise$$internal$$reject(promise, reason) {
        if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
        promise._state = lib$es6$promise$$internal$$REJECTED;
        promise._result = reason;

        lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise);
    }

    function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
        var subscribers = parent._subscribers;
        var length = subscribers.length;

        parent._onerror = null;

        subscribers[length] = child;
        subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment;
        subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection;

        if (length === 0 && parent._state) {
            lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent);
        }
    }

    function lib$es6$promise$$internal$$publish(promise) {
        var subscribers = promise._subscribers;
        var settled = promise._state;

        if (subscribers.length === 0) { return; }

        var child, callback, detail = promise._result;

        for (var i = 0; i < subscribers.length; i += 3) {
            child = subscribers[i];
            callback = subscribers[i + settled];

            if (child) {
                lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail);
            } else {
                callback(detail);
            }
        }

        promise._subscribers.length = 0;
    }

    function lib$es6$promise$$internal$$ErrorObject() {
        this.error = null;
    }

    var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject();

    function lib$es6$promise$$internal$$tryCatch(callback, detail) {
        try {
            return callback(detail);
        } catch (e) {
            lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e;
            return lib$es6$promise$$internal$$TRY_CATCH_ERROR;
        }
    }

    function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) {
        var hasCallback = lib$es6$promise$utils$$isFunction(callback),
            value, error, succeeded, failed;

        if (hasCallback) {
            value = lib$es6$promise$$internal$$tryCatch(callback, detail);

            if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) {
                failed = true;
                error = value.error;
                value = null;
            } else {
                succeeded = true;
            }

            if (promise === value) {
                lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn());
                return;
            }

        } else {
            value = detail;
            succeeded = true;
        }

        if (promise._state !== lib$es6$promise$$internal$$PENDING) {
            // noop
        } else if (hasCallback && succeeded) {
            lib$es6$promise$$internal$$resolve(promise, value);
        } else if (failed) {
            lib$es6$promise$$internal$$reject(promise, error);
        } else if (settled === lib$es6$promise$$internal$$FULFILLED) {
            lib$es6$promise$$internal$$fulfill(promise, value);
        } else if (settled === lib$es6$promise$$internal$$REJECTED) {
            lib$es6$promise$$internal$$reject(promise, value);
        }
    }

    function lib$es6$promise$$internal$$initializePromise(promise, resolver) {
        try {
            resolver(function resolvePromise(value) {
                lib$es6$promise$$internal$$resolve(promise, value);
            }, function rejectPromise(reason) {
                lib$es6$promise$$internal$$reject(promise, reason);
            });
        } catch (e) {
            lib$es6$promise$$internal$$reject(promise, e);
        }
    }

    var lib$es6$promise$$internal$$id = 0;
    function lib$es6$promise$$internal$$nextId() {
        return lib$es6$promise$$internal$$id++;
    }

    function lib$es6$promise$$internal$$makePromise(promise) {
        promise[lib$es6$promise$$internal$$PROMISE_ID] = lib$es6$promise$$internal$$id++;
        promise._state = undefined;
        promise._result = undefined;
        promise._subscribers = [];
    }

    function lib$es6$promise$promise$all$$all(entries) {
        return new lib$es6$promise$enumerator$$default(this, entries).promise;
    }
    var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all;
    function lib$es6$promise$promise$race$$race(entries) {
        /*jshint validthis:true */
        var Constructor = this;

        if (!lib$es6$promise$utils$$isArray(entries)) {
            return new Constructor(function (resolve, reject) {
                reject(new TypeError('You must pass an array to race.'));
            });
        } else {
            return new Constructor(function (resolve, reject) {
                var length = entries.length;
                for (var i = 0; i < length; i++) {
                    Constructor.resolve(entries[i]).then(resolve, reject);
                }
            });
        }
    }
    var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race;
    function lib$es6$promise$promise$reject$$reject(reason) {
        /*jshint validthis:true */
        var Constructor = this;
        var promise = new Constructor(lib$es6$promise$$internal$$noop);
        lib$es6$promise$$internal$$reject(promise, reason);
        return promise;
    }
    var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject;


    function lib$es6$promise$promise$$needsResolver() {
        throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
    }

    function lib$es6$promise$promise$$needsNew() {
        throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
    }

    var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise;
    /**
      Promise objects represent the eventual result of an asynchronous operation. The
      primary way of interacting with a promise is through its `then` method, which
      registers callbacks to receive either a promise's eventual value or the reason
      why the promise cannot be fulfilled.

      Terminology
      -----------

      - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
      - `thenable` is an object or function that defines a `then` method.
      - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
      - `exception` is a value that is thrown using the throw statement.
      - `reason` is a value that indicates why a promise was rejected.
      - `settled` the final resting state of a promise, fulfilled or rejected.

      A promise can be in one of three states: pending, fulfilled, or rejected.

      Promises that are fulfilled have a fulfillment value and are in the fulfilled
      state.  Promises that are rejected have a rejection reason and are in the
      rejected state.  A fulfillment value is never a thenable.

      Promises can also be said to *resolve* a value.  If this value is also a
      promise, then the original promise's settled state will match the value's
      settled state.  So a promise that *resolves* a promise that rejects will
      itself reject, and a promise that *resolves* a promise that fulfills will
      itself fulfill.


      Basic Usage:
      ------------

      ```js
      var promise = new Promise(function(resolve, reject) {
        // on success
        resolve(value);

        // on failure
        reject(reason);
      });

      promise.then(function(value) {
        // on fulfillment
      }, function(reason) {
        // on rejection
      });
      ```

      Advanced Usage:
      ---------------

      Promises shine when abstracting away asynchronous interactions such as
      `XMLHttpRequest`s.

      ```js
      function getJSON(url) {
        return new Promise(function(resolve, reject){
          var xhr = new XMLHttpRequest();

          xhr.open('GET', url);
          xhr.onreadystatechange = handler;
          xhr.responseType = 'json';
          xhr.setRequestHeader('Accept', 'application/json');
          xhr.send();

          function handler() {
            if (this.readyState === this.DONE) {
              if (this.status === 200) {
                resolve(this.response);
              } else {
                reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
              }
            }
          };
        });
      }

      getJSON('/posts.json').then(function(json) {
        // on fulfillment
      }, function(reason) {
        // on rejection
      });
      ```

      Unlike callbacks, promises are great composable primitives.

      ```js
      Promise.all([
        getJSON('/posts'),
        getJSON('/comments')
      ]).then(function(values){
        values[0] // => postsJSON
        values[1] // => commentsJSON

        return values;
      });
      ```

      @class Promise
      @param {function} resolver
      Useful for tooling.
      @constructor
    */
    function lib$es6$promise$promise$$Promise(resolver) {
        this[lib$es6$promise$$internal$$PROMISE_ID] = lib$es6$promise$$internal$$nextId();
        this._result = this._state = undefined;
        this._subscribers = [];

        if (lib$es6$promise$$internal$$noop !== resolver) {
            typeof resolver !== 'function' && lib$es6$promise$promise$$needsResolver();
            this instanceof lib$es6$promise$promise$$Promise ? lib$es6$promise$$internal$$initializePromise(this, resolver) : lib$es6$promise$promise$$needsNew();
        }
    }

    lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;
    lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;
    lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;
    lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;
    lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler;
    lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap;
    lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap;

    lib$es6$promise$promise$$Promise.prototype = {
        constructor: lib$es6$promise$promise$$Promise,

        /**
          The primary way of interacting with a promise is through its `then` method,
          which registers callbacks to receive either a promise's eventual value or the
          reason why the promise cannot be fulfilled.
    
          ```js
          findUser().then(function(user){
            // user is available
          }, function(reason){
            // user is unavailable, and you are given the reason why
          });
          ```
    
          Chaining
          --------
    
          The return value of `then` is itself a promise.  This second, 'downstream'
          promise is resolved with the return value of the first promise's fulfillment
          or rejection handler, or rejected if the handler throws an exception.
    
          ```js
          findUser().then(function (user) {
            return user.name;
          }, function (reason) {
            return 'default name';
          }).then(function (userName) {
            // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
            // will be `'default name'`
          });
    
          findUser().then(function (user) {
            throw new Error('Found user, but still unhappy');
          }, function (reason) {
            throw new Error('`findUser` rejected and we're unhappy');
          }).then(function (value) {
            // never reached
          }, function (reason) {
            // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
            // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
          });
          ```
          If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
    
          ```js
          findUser().then(function (user) {
            throw new PedagogicalException('Upstream error');
          }).then(function (value) {
            // never reached
          }).then(function (value) {
            // never reached
          }, function (reason) {
            // The `PedgagocialException` is propagated all the way down to here
          });
          ```
    
          Assimilation
          ------------
    
          Sometimes the value you want to propagate to a downstream promise can only be
          retrieved asynchronously. This can be achieved by returning a promise in the
          fulfillment or rejection handler. The downstream promise will then be pending
          until the returned promise is settled. This is called *assimilation*.
    
          ```js
          findUser().then(function (user) {
            return findCommentsByAuthor(user);
          }).then(function (comments) {
            // The user's comments are now available
          });
          ```
    
          If the assimliated promise rejects, then the downstream promise will also reject.
    
          ```js
          findUser().then(function (user) {
            return findCommentsByAuthor(user);
          }).then(function (comments) {
            // If `findCommentsByAuthor` fulfills, we'll have the value here
          }, function (reason) {
            // If `findCommentsByAuthor` rejects, we'll have the reason here
          });
          ```
    
          Simple Example
          --------------
    
          Synchronous Example
    
          ```javascript
          var result;
    
          try {
            result = findResult();
            // success
          } catch(reason) {
            // failure
          }
          ```
    
          Errback Example
    
          ```js
          findResult(function(result, err){
            if (err) {
              // failure
            } else {
              // success
            }
          });
          ```
    
          Promise Example;
    
          ```javascript
          findResult().then(function(result){
            // success
          }, function(reason){
            // failure
          });
          ```
    
          Advanced Example
          --------------
    
          Synchronous Example
    
          ```javascript
          var author, books;
    
          try {
            author = findAuthor();
            books  = findBooksByAuthor(author);
            // success
          } catch(reason) {
            // failure
          }
          ```
    
          Errback Example
    
          ```js
    
          function foundBooks(books) {
    
          }
    
          function failure(reason) {
    
          }
    
          findAuthor(function(author, err){
            if (err) {
              failure(err);
              // failure
            } else {
              try {
                findBoooksByAuthor(author, function(books, err) {
                  if (err) {
                    failure(err);
                  } else {
                    try {
                      foundBooks(books);
                    } catch(reason) {
                      failure(reason);
                    }
                  }
                });
              } catch(error) {
                failure(err);
              }
              // success
            }
          });
          ```
    
          Promise Example;
    
          ```javascript
          findAuthor().
            then(findBooksByAuthor).
            then(function(books){
              // found books
          }).catch(function(reason){
            // something went wrong
          });
          ```
    
          @method then
          @param {Function} onFulfilled
          @param {Function} onRejected
          Useful for tooling.
          @return {Promise}
        */
        then: lib$es6$promise$then$$default,

        /**
          `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
          as the catch block of a try/catch statement.
    
          ```js
          function findAuthor(){
            throw new Error('couldn't find that author');
          }
    
          // synchronous
          try {
            findAuthor();
          } catch(reason) {
            // something went wrong
          }
    
          // async with promises
          findAuthor().catch(function(reason){
            // something went wrong
          });
          ```
    
          @method catch
          @param {Function} onRejection
          Useful for tooling.
          @return {Promise}
        */
        'catch': function (onRejection) {
            return this.then(null, onRejection);
        }
    };
    var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator;
    function lib$es6$promise$enumerator$$Enumerator(Constructor, input) {
        this._instanceConstructor = Constructor;
        this.promise = new Constructor(lib$es6$promise$$internal$$noop);

        if (!this.promise[lib$es6$promise$$internal$$PROMISE_ID]) {
            lib$es6$promise$$internal$$makePromise(this.promise);
        }

        if (Array.isArray(input)) {
            this._input = input;
            this.length = input.length;
            this._remaining = input.length;

            this._result = new Array(this.length);

            if (this.length === 0) {
                lib$es6$promise$$internal$$fulfill(this.promise, this._result);
            } else {
                this.length = this.length || 0;
                this._enumerate();
                if (this._remaining === 0) {
                    lib$es6$promise$$internal$$fulfill(this.promise, this._result);
                }
            }
        } else {
            lib$es6$promise$$internal$$reject(this.promise, lib$es6$promise$enumerator$$validationError());
        }
    }

    function lib$es6$promise$enumerator$$validationError() {
        return new Error('Array Methods must be provided an Array');
    }

    lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function () {
        var length = this.length;
        var input = this._input;

        for (var i = 0; this._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
            this._eachEntry(input[i], i);
        }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function (entry, i) {
        var c = this._instanceConstructor;
        var resolve = c.resolve;

        if (resolve === lib$es6$promise$promise$resolve$$default) {
            var then = lib$es6$promise$$internal$$getThen(entry);

            if (then === lib$es6$promise$then$$default &&
                entry._state !== lib$es6$promise$$internal$$PENDING) {
                this._settledAt(entry._state, i, entry._result);
            } else if (typeof then !== 'function') {
                this._remaining--;
                this._result[i] = entry;
            } else if (c === lib$es6$promise$promise$$default) {
                var promise = new c(lib$es6$promise$$internal$$noop);
                lib$es6$promise$$internal$$handleMaybeThenable(promise, entry, then);
                this._willSettleAt(promise, i);
            } else {
                this._willSettleAt(new c(function (resolve) { resolve(entry); }), i);
            }
        } else {
            this._willSettleAt(resolve(entry), i);
        }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function (state, i, value) {
        var promise = this.promise;

        if (promise._state === lib$es6$promise$$internal$$PENDING) {
            this._remaining--;

            if (state === lib$es6$promise$$internal$$REJECTED) {
                lib$es6$promise$$internal$$reject(promise, value);
            } else {
                this._result[i] = value;
            }
        }

        if (this._remaining === 0) {
            lib$es6$promise$$internal$$fulfill(promise, this._result);
        }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function (promise, i) {
        var enumerator = this;

        lib$es6$promise$$internal$$subscribe(promise, undefined, function (value) {
            enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value);
        }, function (reason) {
            enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason);
        });
    };
    function lib$es6$promise$polyfill$$polyfill() {
        var local;

        if (typeof global !== 'undefined') {
            local = global;
        } else if (typeof self !== 'undefined') {
            local = self;
        } else {
            try {
                local = Function('return this')();
            } catch (e) {
                throw new Error('polyfill failed because global object is unavailable in this environment');
            }
        }

        var P = local.Promise;

        if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) {
            return;
        }

        local.Promise = lib$es6$promise$promise$$default;
    }
    var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;

    var lib$es6$promise$umd$$ES6Promise = {
        'Promise': lib$es6$promise$promise$$default,
        'polyfill': lib$es6$promise$polyfill$$default
    };

    /* global define:true module:true window: true */
    // if (typeof define === 'function' && define['amd']) {
    //     define(function () { return lib$es6$promise$umd$$ES6Promise; });
    // } else if (typeof module !== 'undefined' && module['exports']) {
    //     module['exports'] = lib$es6$promise$umd$$ES6Promise;
    // } else if (typeof this !== 'undefined') {
    //     this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise;
    // }

    lib$es6$promise$polyfill$$default();
    
    __promise.ES6Promise = lib$es6$promise$umd$$ES6Promise    
};

var __LiteMolPromise;

if (typeof window !== 'undefined' && window && window.Promise) {
    __LiteMolPromise = window.Promise;
} else if (typeof global !== 'undefined' && global && global.Promise) {
    __LiteMolPromise = global.Promise;
} else {
    var __promise = {};
    __createPromise(__promise);
    __LiteMolPromise = __promise.ES6Promise.Promise;
}


// Copyright (c) Microsoft, All rights reserved. See License.txt in the project root for license information.

/*
 * Copyright (c) Microsoft.  All rights reserved.
Microsoft Open Technologies would like to thank its contributors, a list
of whom are at http://rx.codeplex.com/wikipage?title=Contributors.

Licensed under the Apache License, Version 2.0 (the "License"); you
may not use this file except in compliance with the License. You may
obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing permissions
and limitations under the License.
 * 
 */

var __LiteMolRxTemp = {};

; (function (__LMtarget, __LMpromise, undefined) {

    var objectTypes = {
        'function': true,
        'object': true
    };

    function checkGlobal(value) {
        return (value && value.Object === Object) ? value : null;
    }

    var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : null;
    var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : null;
    var freeGlobal = checkGlobal(freeExports && freeModule && typeof global === 'object' && global);
    var freeSelf = checkGlobal(objectTypes[typeof self] && self);
    var freeWindow = checkGlobal(objectTypes[typeof window] && window);
    var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports : null;
    var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
    var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')();

    var Rx = {
        internals: {},
        config: {
            Promise: __LMpromise
        },
        helpers: {}
    };

    // Defaults
    var noop = Rx.helpers.noop = function () { },
      identity = Rx.helpers.identity = function (x) { return x; },
      defaultNow = Rx.helpers.defaultNow = Date.now,
      defaultComparer = Rx.helpers.defaultComparer = function (x, y) { return isEqual(x, y); },
      defaultSubComparer = Rx.helpers.defaultSubComparer = function (x, y) { return x > y ? 1 : (x < y ? -1 : 0); },
      defaultKeySerializer = Rx.helpers.defaultKeySerializer = function (x) { return x.toString(); },
      defaultError = Rx.helpers.defaultError = function (err) { throw err; },
      isPromise = Rx.helpers.isPromise = function (p) { return !!p && typeof p.subscribe !== 'function' && typeof p.then === 'function'; },
      isFunction = Rx.helpers.isFunction = (function () {

          var isFn = function (value) {
              return typeof value == 'function' || false;
          };

          // fallback for older versions of Chrome and Safari
          if (isFn(/x/)) {
              isFn = function (value) {
                  return typeof value == 'function' && toString.call(value) == '[object Function]';
              };
          }

          return isFn;
      }());

    function cloneArray(arr) {
        var len = arr.length, a = new Array(len);
        for (var i = 0; i < len; i++) { a[i] = arr[i]; }
        return a;
    }

    var errorObj = { e: {} };

    function tryCatcherGen(tryCatchTarget) {
        return function tryCatcher() {
            try {
                return tryCatchTarget.apply(this, arguments);
            } catch (e) {
                errorObj.e = e;
                return errorObj;
            }
        };
    }

    var tryCatch = Rx.internals.tryCatch = function tryCatch(fn) {
        if (!isFunction(fn)) { throw new TypeError('fn must be a function'); }
        return tryCatcherGen(fn);
    };

    function thrower(e) {
        throw e;
    }

    Rx.config.longStackSupport = false;
    var hasStacks = false, stacks = tryCatch(function () { throw new Error(); })();
    hasStacks = !!stacks.e && !!stacks.e.stack;

    // All code after this point will be filtered from stack traces reported by RxJS
    var rStartingLine = captureLine(), rFileName;

    var STACK_JUMP_SEPARATOR = 'From previous event:';

    function makeStackTraceLong(error, observable) {
        // If possible, transform the error stack trace by removing Node and RxJS
        // cruft, then concatenating with the stack trace of `observable`.
        if (hasStacks &&
            observable.stack &&
            typeof error === 'object' &&
            error !== null &&
            error.stack &&
            error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
        ) {
            var stacks = [];
            for (var o = observable; !!o; o = o.source) {
                if (o.stack) {
                    stacks.unshift(o.stack);
                }
            }
            stacks.unshift(error.stack);

            var concatedStacks = stacks.join('\n' + STACK_JUMP_SEPARATOR + '\n');
            error.stack = filterStackString(concatedStacks);
        }
    }

    function filterStackString(stackString) {
        var lines = stackString.split('\n'), desiredLines = [];
        for (var i = 0, len = lines.length; i < len; i++) {
            var line = lines[i];

            if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
                desiredLines.push(line);
            }
        }
        return desiredLines.join('\n');
    }

    function isInternalFrame(stackLine) {
        var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);
        if (!fileNameAndLineNumber) {
            return false;
        }
        var fileName = fileNameAndLineNumber[0], lineNumber = fileNameAndLineNumber[1];

        return fileName === rFileName &&
          lineNumber >= rStartingLine &&
          lineNumber <= rEndingLine;
    }

    function isNodeFrame(stackLine) {
        return stackLine.indexOf('(module.js:') !== -1 ||
          stackLine.indexOf('(node.js:') !== -1;
    }

    function captureLine() {
        if (!hasStacks) { return; }

        try {
            throw new Error();
        } catch (e) {
            var lines = e.stack.split('\n');
            var firstLine = lines[0].indexOf('@') > 0 ? lines[1] : lines[2];
            var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
            if (!fileNameAndLineNumber) { return; }

            rFileName = fileNameAndLineNumber[0];
            return fileNameAndLineNumber[1];
        }
    }

    function getFileNameAndLineNumber(stackLine) {
        // Named functions: 'at functionName (filename:lineNumber:columnNumber)'
        var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
        if (attempt1) { return [attempt1[1], Number(attempt1[2])]; }

        // Anonymous functions: 'at filename:lineNumber:columnNumber'
        var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
        if (attempt2) { return [attempt2[1], Number(attempt2[2])]; }

        // Firefox style: 'function@filename:lineNumber or @filename:lineNumber'
        var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
        if (attempt3) { return [attempt3[1], Number(attempt3[2])]; }
    }

    var EmptyError = Rx.EmptyError = function () {
        this.message = 'Sequence contains no elements.';
        Error.call(this);
    };
    EmptyError.prototype = Object.create(Error.prototype);
    EmptyError.prototype.name = 'EmptyError';

    var ObjectDisposedError = Rx.ObjectDisposedError = function () {
        this.message = 'Object has been disposed';
        Error.call(this);
    };
    ObjectDisposedError.prototype = Object.create(Error.prototype);
    ObjectDisposedError.prototype.name = 'ObjectDisposedError';

    var ArgumentOutOfRangeError = Rx.ArgumentOutOfRangeError = function () {
        this.message = 'Argument out of range';
        Error.call(this);
    };
    ArgumentOutOfRangeError.prototype = Object.create(Error.prototype);
    ArgumentOutOfRangeError.prototype.name = 'ArgumentOutOfRangeError';

    var NotSupportedError = Rx.NotSupportedError = function (message) {
        this.message = message || 'This operation is not supported';
        Error.call(this);
    };
    NotSupportedError.prototype = Object.create(Error.prototype);
    NotSupportedError.prototype.name = 'NotSupportedError';

    var NotImplementedError = Rx.NotImplementedError = function (message) {
        this.message = message || 'This operation is not implemented';
        Error.call(this);
    };
    NotImplementedError.prototype = Object.create(Error.prototype);
    NotImplementedError.prototype.name = 'NotImplementedError';

    var notImplemented = Rx.helpers.notImplemented = function () {
        throw new NotImplementedError();
    };

    var notSupported = Rx.helpers.notSupported = function () {
        throw new NotSupportedError();
    };

    // Shim in iterator support
    var $iterator$ = (typeof Symbol === 'function' && Symbol.iterator) ||
      '_es6shim_iterator_';
    // Bug for mozilla version
    if (root.Set && typeof new root.Set()['@@iterator'] === 'function') {
        $iterator$ = '@@iterator';
    }

    var doneEnumerator = Rx.doneEnumerator = { done: true, value: undefined };

    var isIterable = Rx.helpers.isIterable = function (o) {
        return o && o[$iterator$] !== undefined;
    };

    var isArrayLike = Rx.helpers.isArrayLike = function (o) {
        return o && o.length !== undefined;
    };

    Rx.helpers.iterator = $iterator$;

    var bindCallback = Rx.internals.bindCallback = function (func, thisArg, argCount) {
        if (typeof thisArg === 'undefined') { return func; }
        switch (argCount) {
            case 0:
                return function () {
                    return func.call(thisArg)
                };
            case 1:
                return function (arg) {
                    return func.call(thisArg, arg);
                };
            case 2:
                return function (value, index) {
                    return func.call(thisArg, value, index);
                };
            case 3:
                return function (value, index, collection) {
                    return func.call(thisArg, value, index, collection);
                };
        }

        return function () {
            return func.apply(thisArg, arguments);
        };
    };

    /** Used to determine if values are of the language type Object */
    var dontEnums = ['toString',
      'toLocaleString',
      'valueOf',
      'hasOwnProperty',
      'isPrototypeOf',
      'propertyIsEnumerable',
      'constructor'],
    dontEnumsLength = dontEnums.length;

    var argsTag = '[object Arguments]',
        arrayTag = '[object Array]',
        boolTag = '[object Boolean]',
        dateTag = '[object Date]',
        errorTag = '[object Error]',
        funcTag = '[object Function]',
        mapTag = '[object Map]',
        numberTag = '[object Number]',
        objectTag = '[object Object]',
        regexpTag = '[object RegExp]',
        setTag = '[object Set]',
        stringTag = '[object String]',
        weakMapTag = '[object WeakMap]';

    var arrayBufferTag = '[object ArrayBuffer]',
        float32Tag = '[object Float32Array]',
        float64Tag = '[object Float64Array]',
        int8Tag = '[object Int8Array]',
        int16Tag = '[object Int16Array]',
        int32Tag = '[object Int32Array]',
        uint8Tag = '[object Uint8Array]',
        uint8ClampedTag = '[object Uint8ClampedArray]',
        uint16Tag = '[object Uint16Array]',
        uint32Tag = '[object Uint32Array]';

    var typedArrayTags = {};
    typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
    typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
    typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
    typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
    typedArrayTags[uint32Tag] = true;
    typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
    typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
    typedArrayTags[dateTag] = typedArrayTags[errorTag] =
    typedArrayTags[funcTag] = typedArrayTags[mapTag] =
    typedArrayTags[numberTag] = typedArrayTags[objectTag] =
    typedArrayTags[regexpTag] = typedArrayTags[setTag] =
    typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;

    var objectProto = Object.prototype,
        hasOwnProperty = objectProto.hasOwnProperty,
        objToString = objectProto.toString,
        MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;

    var keys = Object.keys || (function () {
        var hasOwnProperty = Object.prototype.hasOwnProperty,
            hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
            dontEnums = [
              'toString',
              'toLocaleString',
              'valueOf',
              'hasOwnProperty',
              'isPrototypeOf',
              'propertyIsEnumerable',
              'constructor'
            ],
            dontEnumsLength = dontEnums.length;

        return function (obj) {
            if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
                throw new TypeError('Object.keys called on non-object');
            }

            var result = [], prop, i;

            for (prop in obj) {
                if (hasOwnProperty.call(obj, prop)) {
                    result.push(prop);
                }
            }

            if (hasDontEnumBug) {
                for (i = 0; i < dontEnumsLength; i++) {
                    if (hasOwnProperty.call(obj, dontEnums[i])) {
                        result.push(dontEnums[i]);
                    }
                }
            }
            return result;
        };
    }());

    function equalObjects(object, other, equalFunc, isLoose, stackA, stackB) {
        var objProps = keys(object),
            objLength = objProps.length,
            othProps = keys(other),
            othLength = othProps.length;

        if (objLength !== othLength && !isLoose) {
            return false;
        }
        var index = objLength, key;
        while (index--) {
            key = objProps[index];
            if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
                return false;
            }
        }
        var skipCtor = isLoose;
        while (++index < objLength) {
            key = objProps[index];
            var objValue = object[key],
                othValue = other[key],
                result;

            if (!(result === undefined ? equalFunc(objValue, othValue, isLoose, stackA, stackB) : result)) {
                return false;
            }
            skipCtor || (skipCtor = key === 'constructor');
        }
        if (!skipCtor) {
            var objCtor = object.constructor,
                othCtor = other.constructor;

            if (objCtor !== othCtor &&
                ('constructor' in object && 'constructor' in other) &&
                !(typeof objCtor === 'function' && objCtor instanceof objCtor &&
                  typeof othCtor === 'function' && othCtor instanceof othCtor)) {
                return false;
            }
        }
        return true;
    }

    function equalByTag(object, other, tag) {
        switch (tag) {
            case boolTag:
            case dateTag:
                return +object === +other;

            case errorTag:
                return object.name === other.name && object.message === other.message;

            case numberTag:
                return (object !== +object) ?
                  other !== +other :
                  object === +other;

            case regexpTag:
            case stringTag:
                return object === (other + '');
        }
        return false;
    }

    var isObject = Rx.internals.isObject = function (value) {
        var type = typeof value;
        return !!value && (type === 'object' || type === 'function');
    };

    function isObjectLike(value) {
        return !!value && typeof value === 'object';
    }

    function isLength(value) {
        return typeof value === 'number' && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER;
    }

    var isHostObject = (function () {
        try {
            Object({ 'toString': 0 } + '');
        } catch (e) {
            return function () { return false; };
        }
        return function (value) {
            return typeof value.toString !== 'function' && typeof (value + '') === 'string';
        };
    }());

    function isTypedArray(value) {
        return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
    }

    var isArray = Array.isArray || function (value) {
        return isObjectLike(value) && isLength(value.length) && objToString.call(value) === arrayTag;
    };

    function arraySome(array, predicate) {
        var index = -1,
            length = array.length;

        while (++index < length) {
            if (predicate(array[index], index, array)) {
                return true;
            }
        }
        return false;
    }

    function equalArrays(array, other, equalFunc, isLoose, stackA, stackB) {
        var index = -1,
            arrLength = array.length,
            othLength = other.length;

        if (arrLength !== othLength && !(isLoose && othLength > arrLength)) {
            return false;
        }
        // Ignore non-index properties.
        while (++index < arrLength) {
            var arrValue = array[index],
                othValue = other[index],
                result;

            if (result !== undefined) {
                if (result) {
                    continue;
                }
                return false;
            }
            // Recursively compare arrays (susceptible to call stack limits).
            if (isLoose) {
                if (!arraySome(other, function (othValue) {
                      return arrValue === othValue || equalFunc(arrValue, othValue, isLoose, stackA, stackB);
                })) {
                    return false;
                }
            } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, isLoose, stackA, stackB))) {
                return false;
            }
        }
        return true;
    }

    function baseIsEqualDeep(object, other, equalFunc, isLoose, stackA, stackB) {
        var objIsArr = isArray(object),
            othIsArr = isArray(other),
            objTag = arrayTag,
            othTag = arrayTag;

        if (!objIsArr) {
            objTag = objToString.call(object);
            if (objTag === argsTag) {
                objTag = objectTag;
            } else if (objTag !== objectTag) {
                objIsArr = isTypedArray(object);
            }
        }
        if (!othIsArr) {
            othTag = objToString.call(other);
            if (othTag === argsTag) {
                othTag = objectTag;
            }
        }
        var objIsObj = objTag === objectTag && !isHostObject(object),
            othIsObj = othTag === objectTag && !isHostObject(other),
            isSameTag = objTag === othTag;

        if (isSameTag && !(objIsArr || objIsObj)) {
            return equalByTag(object, other, objTag);
        }
        if (!isLoose) {
            var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
                othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

            if (objIsWrapped || othIsWrapped) {
                return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, isLoose, stackA, stackB);
            }
        }
        if (!isSameTag) {
            return false;
        }
        // Assume cyclic values are equal.
        // For more information on detecting circular references see https://es5.github.io/#JO.
        stackA || (stackA = []);
        stackB || (stackB = []);

        var length = stackA.length;
        while (length--) {
            if (stackA[length] === object) {
                return stackB[length] === other;
            }
        }
        // Add `object` and `other` to the stack of traversed objects.
        stackA.push(object);
        stackB.push(other);

        var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, isLoose, stackA, stackB);

        stackA.pop();
        stackB.pop();

        return result;
    }

    function baseIsEqual(value, other, isLoose, stackA, stackB) {
        if (value === other) {
            return true;
        }
        if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
            return value !== value && other !== other;
        }
        return baseIsEqualDeep(value, other, baseIsEqual, isLoose, stackA, stackB);
    }

    var isEqual = Rx.internals.isEqual = function (value, other) {
        return baseIsEqual(value, other);
    };

    var hasProp = {}.hasOwnProperty,
        slice = Array.prototype.slice;

    var inherits = Rx.internals.inherits = function (child, parent) {
        function __() { this.constructor = child; }
        __.prototype = parent.prototype;
        child.prototype = new __();
    };

    var addProperties = Rx.internals.addProperties = function (obj) {
        for (var sources = [], i = 1, len = arguments.length; i < len; i++) { sources.push(arguments[i]); }
        for (var idx = 0, ln = sources.length; idx < ln; idx++) {
            var source = sources[idx];
            for (var prop in source) {
                obj[prop] = source[prop];
            }
        }
    };

    // Rx Utils
    var addRef = Rx.internals.addRef = function (xs, r) {
        return new AnonymousObservable(function (observer) {
            return new BinaryDisposable(r.getDisposable(), xs.subscribe(observer));
        });
    };

    function arrayInitialize(count, factory) {
        var a = new Array(count);
        for (var i = 0; i < count; i++) {
            a[i] = factory();
        }
        return a;
    }

    /**
     * Represents a group of disposable resources that are disposed together.
     * @constructor
     */
    var CompositeDisposable = Rx.CompositeDisposable = function () {
        var args = [], i, len;
        if (Array.isArray(arguments[0])) {
            args = arguments[0];
        } else {
            len = arguments.length;
            args = new Array(len);
            for (i = 0; i < len; i++) { args[i] = arguments[i]; }
        }
        this.disposables = args;
        this.isDisposed = false;
        this.length = args.length;
    };

    var CompositeDisposablePrototype = CompositeDisposable.prototype;

    /**
     * Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed.
     * @param {Mixed} item Disposable to add.
     */
    CompositeDisposablePrototype.add = function (item) {
        if (this.isDisposed) {
            item.dispose();
        } else {
            this.disposables.push(item);
            this.length++;
        }
    };

    /**
     * Removes and disposes the first occurrence of a disposable from the CompositeDisposable.
     * @param {Mixed} item Disposable to remove.
     * @returns {Boolean} true if found; false otherwise.
     */
    CompositeDisposablePrototype.remove = function (item) {
        var shouldDispose = false;
        if (!this.isDisposed) {
            var idx = this.disposables.indexOf(item);
            if (idx !== -1) {
                shouldDispose = true;
                this.disposables.splice(idx, 1);
                this.length--;
                item.dispose();
            }
        }
        return shouldDispose;
    };

    /**
     *  Disposes all disposables in the group and removes them from the group.
     */
    CompositeDisposablePrototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            var len = this.disposables.length, currentDisposables = new Array(len);
            for (var i = 0; i < len; i++) { currentDisposables[i] = this.disposables[i]; }
            this.disposables = [];
            this.length = 0;

            for (i = 0; i < len; i++) {
                currentDisposables[i].dispose();
            }
        }
    };

    /**
     * Provides a set of static methods for creating Disposables.
     * @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once.
     */
    var Disposable = Rx.Disposable = function (action) {
        this.isDisposed = false;
        this.action = action || noop;
    };

    /** Performs the task of cleaning up resources. */
    Disposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.action();
            this.isDisposed = true;
        }
    };

    /**
     * Creates a disposable object that invokes the specified action when disposed.
     * @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once.
     * @return {Disposable} The disposable object that runs the given action upon disposal.
     */
    var disposableCreate = Disposable.create = function (action) { return new Disposable(action); };

    /**
     * Gets the disposable that does nothing when disposed.
     */
    var disposableEmpty = Disposable.empty = { dispose: noop };

    /**
     * Validates whether the given object is a disposable
     * @param {Object} Object to test whether it has a dispose method
     * @returns {Boolean} true if a disposable object, else false.
     */
    var isDisposable = Disposable.isDisposable = function (d) {
        return d && isFunction(d.dispose);
    };

    var checkDisposed = Disposable.checkDisposed = function (disposable) {
        if (disposable.isDisposed) { throw new ObjectDisposedError(); }
    };

    var disposableFixup = Disposable._fixup = function (result) {
        return isDisposable(result) ? result : disposableEmpty;
    };

    // Single assignment
    var SingleAssignmentDisposable = Rx.SingleAssignmentDisposable = function () {
        this.isDisposed = false;
        this.current = null;
    };
    SingleAssignmentDisposable.prototype.getDisposable = function () {
        return this.current;
    };
    SingleAssignmentDisposable.prototype.setDisposable = function (value) {
        if (this.current) { throw new Error('Disposable has already been assigned'); }
        var shouldDispose = this.isDisposed;
        !shouldDispose && (this.current = value);
        shouldDispose && value && value.dispose();
    };
    SingleAssignmentDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            var old = this.current;
            this.current = null;
            old && old.dispose();
        }
    };

    // Multiple assignment disposable
    var SerialDisposable = Rx.SerialDisposable = function () {
        this.isDisposed = false;
        this.current = null;
    };
    SerialDisposable.prototype.getDisposable = function () {
        return this.current;
    };
    SerialDisposable.prototype.setDisposable = function (value) {
        var shouldDispose = this.isDisposed;
        if (!shouldDispose) {
            var old = this.current;
            this.current = value;
        }
        old && old.dispose();
        shouldDispose && value && value.dispose();
    };
    SerialDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            var old = this.current;
            this.current = null;
        }
        old && old.dispose();
    };

    var BinaryDisposable = Rx.BinaryDisposable = function (first, second) {
        this._first = first;
        this._second = second;
        this.isDisposed = false;
    };

    BinaryDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            var old1 = this._first;
            this._first = null;
            old1 && old1.dispose();
            var old2 = this._second;
            this._second = null;
            old2 && old2.dispose();
        }
    };

    var NAryDisposable = Rx.NAryDisposable = function (disposables) {
        this._disposables = disposables;
        this.isDisposed = false;
    };

    NAryDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            for (var i = 0, len = this._disposables.length; i < len; i++) {
                this._disposables[i].dispose();
            }
            this._disposables.length = 0;
        }
    };

    /**
     * Represents a disposable resource that only disposes its underlying disposable resource when all dependent disposable objects have been disposed.
     */
    var RefCountDisposable = Rx.RefCountDisposable = (function () {

        function InnerDisposable(disposable) {
            this.disposable = disposable;
            this.disposable.count++;
            this.isInnerDisposed = false;
        }

        InnerDisposable.prototype.dispose = function () {
            if (!this.disposable.isDisposed && !this.isInnerDisposed) {
                this.isInnerDisposed = true;
                this.disposable.count--;
                if (this.disposable.count === 0 && this.disposable.isPrimaryDisposed) {
                    this.disposable.isDisposed = true;
                    this.disposable.underlyingDisposable.dispose();
                }
            }
        };

        /**
         * Initializes a new instance of the RefCountDisposable with the specified disposable.
         * @constructor
         * @param {Disposable} disposable Underlying disposable.
          */
        function RefCountDisposable(disposable) {
            this.underlyingDisposable = disposable;
            this.isDisposed = false;
            this.isPrimaryDisposed = false;
            this.count = 0;
        }

        /**
         * Disposes the underlying disposable only when all dependent disposables have been disposed
         */
        RefCountDisposable.prototype.dispose = function () {
            if (!this.isDisposed && !this.isPrimaryDisposed) {
                this.isPrimaryDisposed = true;
                if (this.count === 0) {
                    this.isDisposed = true;
                    this.underlyingDisposable.dispose();
                }
            }
        };

        /**
         * Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.
         * @returns {Disposable} A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.
         */
        RefCountDisposable.prototype.getDisposable = function () {
            return this.isDisposed ? disposableEmpty : new InnerDisposable(this);
        };

        return RefCountDisposable;
    })();

    var ScheduledItem = Rx.internals.ScheduledItem = function (scheduler, state, action, dueTime, comparer) {
        this.scheduler = scheduler;
        this.state = state;
        this.action = action;
        this.dueTime = dueTime;
        this.comparer = comparer || defaultSubComparer;
        this.disposable = new SingleAssignmentDisposable();
    };

    ScheduledItem.prototype.invoke = function () {
        this.disposable.setDisposable(this.invokeCore());
    };

    ScheduledItem.prototype.compareTo = function (other) {
        return this.comparer(this.dueTime, other.dueTime);
    };

    ScheduledItem.prototype.isCancelled = function () {
        return this.disposable.isDisposed;
    };

    ScheduledItem.prototype.invokeCore = function () {
        return disposableFixup(this.action(this.scheduler, this.state));
    };

    /** Provides a set of static properties to access commonly used schedulers. */
    var Scheduler = Rx.Scheduler = (function () {

        function Scheduler() { }

        /** Determines whether the given object is a scheduler */
        Scheduler.isScheduler = function (s) {
            return s instanceof Scheduler;
        };

        var schedulerProto = Scheduler.prototype;

        /**
       * Schedules an action to be executed.
       * @param state State passed to the action to be executed.
       * @param {Function} action Action to be executed.
       * @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
       */
        schedulerProto.schedule = function (state, action) {
            throw new NotImplementedError();
        };

        /**
         * Schedules an action to be executed after dueTime.
         * @param state State passed to the action to be executed.
         * @param {Function} action Action to be executed.
         * @param {Number} dueTime Relative time after which to execute the action.
         * @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
         */
        schedulerProto.scheduleFuture = function (state, dueTime, action) {
            var dt = dueTime;
            dt instanceof Date && (dt = dt - this.now());
            dt = Scheduler.normalize(dt);

            if (dt === 0) { return this.schedule(state, action); }

            return this._scheduleFuture(state, dt, action);
        };

        schedulerProto._scheduleFuture = function (state, dueTime, action) {
            throw new NotImplementedError();
        };

        /** Gets the current time according to the local machine's system clock. */
        Scheduler.now = defaultNow;

        /** Gets the current time according to the local machine's system clock. */
        Scheduler.prototype.now = defaultNow;

        /**
         * Normalizes the specified TimeSpan value to a positive value.
         * @param {Number} timeSpan The time span value to normalize.
         * @returns {Number} The specified TimeSpan value if it is zero or positive; otherwise, 0
         */
        Scheduler.normalize = function (timeSpan) {
            timeSpan < 0 && (timeSpan = 0);
            return timeSpan;
        };

        return Scheduler;
    }());

    var normalizeTime = Scheduler.normalize, isScheduler = Scheduler.isScheduler;

    (function (schedulerProto) {

        function invokeRecImmediate(scheduler, pair) {
            var state = pair[0], action = pair[1], group = new CompositeDisposable();
            action(state, innerAction);
            return group;

            function innerAction(state2) {
                var isAdded = false, isDone = false;

                var d = scheduler.schedule(state2, scheduleWork);
                if (!isDone) {
                    group.add(d);
                    isAdded = true;
                }

                function scheduleWork(_, state3) {
                    if (isAdded) {
                        group.remove(d);
                    } else {
                        isDone = true;
                    }
                    action(state3, innerAction);
                    return disposableEmpty;
                }
            }
        }

        function invokeRecDate(scheduler, pair) {
            var state = pair[0], action = pair[1], group = new CompositeDisposable();
            action(state, innerAction);
            return group;

            function innerAction(state2, dueTime1) {
                var isAdded = false, isDone = false;

                var d = scheduler.scheduleFuture(state2, dueTime1, scheduleWork);
                if (!isDone) {
                    group.add(d);
                    isAdded = true;
                }

                function scheduleWork(_, state3) {
                    if (isAdded) {
                        group.remove(d);
                    } else {
                        isDone = true;
                    }
                    action(state3, innerAction);
                    return disposableEmpty;
                }
            }
        }

        /**
         * Schedules an action to be executed recursively.
         * @param {Mixed} state State passed to the action to be executed.
         * @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in recursive invocation state.
         * @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
         */
        schedulerProto.scheduleRecursive = function (state, action) {
            return this.schedule([state, action], invokeRecImmediate);
        };

        /**
         * Schedules an action to be executed recursively after a specified relative or absolute due time.
         * @param {Mixed} state State passed to the action to be executed.
         * @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state.
         * @param {Number | Date} dueTime Relative or absolute time after which to execute the action for the first time.
         * @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
         */
        schedulerProto.scheduleRecursiveFuture = function (state, dueTime, action) {
            return this.scheduleFuture([state, action], dueTime, invokeRecDate);
        };

    }(Scheduler.prototype));

    (function (schedulerProto) {

        /**
         * Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities. The periodic task will be scheduled using window.setInterval for the base implementation.
         * @param {Mixed} state Initial state passed to the action upon the first iteration.
         * @param {Number} period Period for running the work periodically.
         * @param {Function} action Action to be executed, potentially updating the state.
         * @returns {Disposable} The disposable object used to cancel the scheduled recurring action (best effort).
         */
        schedulerProto.schedulePeriodic = function (state, period, action) {
            if (typeof root.setInterval === 'undefined') { throw new NotSupportedError(); }
            period = normalizeTime(period);
            var s = state, id = root.setInterval(function () { s = action(s); }, period);
            return disposableCreate(function () { root.clearInterval(id); });
        };

    }(Scheduler.prototype));

    /** Gets a scheduler that schedules work immediately on the current thread. */
    var ImmediateScheduler = (function (__super__) {
        inherits(ImmediateScheduler, __super__);
        function ImmediateScheduler() {
            __super__.call(this);
        }

        ImmediateScheduler.prototype.schedule = function (state, action) {
            return disposableFixup(action(this, state));
        };

        return ImmediateScheduler;
    }(Scheduler));

    var immediateScheduler = Scheduler.immediate = new ImmediateScheduler();

    /**
     * Gets a scheduler that schedules work as soon as possible on the current thread.
     */
    var CurrentThreadScheduler = (function (__super__) {
        var queue;

        function runTrampoline() {
            while (queue.length > 0) {
                var item = queue.dequeue();
                !item.isCancelled() && item.invoke();
            }
        }

        inherits(CurrentThreadScheduler, __super__);
        function CurrentThreadScheduler() {
            __super__.call(this);
        }

        CurrentThreadScheduler.prototype.schedule = function (state, action) {
            var si = new ScheduledItem(this, state, action, this.now());

            if (!queue) {
                queue = new PriorityQueue(4);
                queue.enqueue(si);

                var result = tryCatch(runTrampoline)();
                queue = null;
                if (result === errorObj) { thrower(result.e); }
            } else {
                queue.enqueue(si);
            }
            return si.disposable;
        };

        CurrentThreadScheduler.prototype.scheduleRequired = function () { return !queue; };

        return CurrentThreadScheduler;
    }(Scheduler));

    var currentThreadScheduler = Scheduler.currentThread = new CurrentThreadScheduler();

    var SchedulePeriodicRecursive = Rx.internals.SchedulePeriodicRecursive = (function () {
        function createTick(self) {
            return function tick(command, recurse) {
                recurse(0, self._period);
                var state = tryCatch(self._action)(self._state);
                if (state === errorObj) {
                    self._cancel.dispose();
                    thrower(state.e);
                }
                self._state = state;
            };
        }

        function SchedulePeriodicRecursive(scheduler, state, period, action) {
            this._scheduler = scheduler;
            this._state = state;
            this._period = period;
            this._action = action;
        }

        SchedulePeriodicRecursive.prototype.start = function () {
            var d = new SingleAssignmentDisposable();
            this._cancel = d;
            d.setDisposable(this._scheduler.scheduleRecursiveFuture(0, this._period, createTick(this)));

            return d;
        };

        return SchedulePeriodicRecursive;
    }());

    var scheduleMethod, clearMethod;

    var localTimer = (function () {
        var localSetTimeout, localClearTimeout = noop;
        if (!!root.setTimeout) {
            localSetTimeout = root.setTimeout;
            localClearTimeout = root.clearTimeout;
        } else if (!!root.WScript) {
            localSetTimeout = function (fn, time) {
                root.WScript.Sleep(time);
                fn();
            };
        } else {
            throw new NotSupportedError();
        }

        return {
            setTimeout: localSetTimeout,
            clearTimeout: localClearTimeout
        };
    }());
    var localSetTimeout = localTimer.setTimeout,
      localClearTimeout = localTimer.clearTimeout;

    (function () {

        var nextHandle = 1, tasksByHandle = {}, currentlyRunning = false;

        clearMethod = function (handle) {
            delete tasksByHandle[handle];
        };

        function runTask(handle) {
            if (currentlyRunning) {
                localSetTimeout(function () { runTask(handle); }, 0);
            } else {
                var task = tasksByHandle[handle];
                if (task) {
                    currentlyRunning = true;
                    var result = tryCatch(task)();
                    clearMethod(handle);
                    currentlyRunning = false;
                    if (result === errorObj) { thrower(result.e); }
                }
            }
        }

        var reNative = new RegExp('^' +
          String(toString)
            .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
            .replace(/toString| for [^\]]+/g, '.*?') + '$'
        );

        var setImmediate = typeof (setImmediate = freeGlobal && moduleExports && freeGlobal.setImmediate) == 'function' &&
          !reNative.test(setImmediate) && setImmediate;

        function postMessageSupported() {
            // Ensure not in a worker
            if (!root.postMessage || root.importScripts) { return false; }
            var isAsync = false, oldHandler = root.onmessage;
            // Test for async
            root.onmessage = function () { isAsync = true; };
            root.postMessage('', '*');
            root.onmessage = oldHandler;

            return isAsync;
        }

        // Use in order, setImmediate, nextTick, postMessage, MessageChannel, script readystatechanged, setTimeout
        if (isFunction(setImmediate)) {
            scheduleMethod = function (action) {
                var id = nextHandle++;
                tasksByHandle[id] = action;
                setImmediate(function () { runTask(id); });

                return id;
            };
        } else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
            scheduleMethod = function (action) {
                var id = nextHandle++;
                tasksByHandle[id] = action;
                process.nextTick(function () { runTask(id); });

                return id;
            };
        } else if (postMessageSupported()) {
            var MSG_PREFIX = 'ms.rx.schedule' + Math.random();

            var onGlobalPostMessage = function (event) {
                // Only if we're a match to avoid any other global events
                if (typeof event.data === 'string' && event.data.substring(0, MSG_PREFIX.length) === MSG_PREFIX) {
                    runTask(event.data.substring(MSG_PREFIX.length));
                }
            };

            root.addEventListener('message', onGlobalPostMessage, false);

            scheduleMethod = function (action) {
                var id = nextHandle++;
                tasksByHandle[id] = action;
                root.postMessage(MSG_PREFIX + id, '*');
                return id;
            };
        } else if (!!root.MessageChannel) {
            var channel = new root.MessageChannel();

            channel.port1.onmessage = function (e) { runTask(e.data); };

            scheduleMethod = function (action) {
                var id = nextHandle++;
                tasksByHandle[id] = action;
                channel.port2.postMessage(id);
                return id;
            };
        } else if ('document' in root && 'onreadystatechange' in root.document.createElement('script')) {

            scheduleMethod = function (action) {
                var scriptElement = root.document.createElement('script');
                var id = nextHandle++;
                tasksByHandle[id] = action;

                scriptElement.onreadystatechange = function () {
                    runTask(id);
                    scriptElement.onreadystatechange = null;
                    scriptElement.parentNode.removeChild(scriptElement);
                    scriptElement = null;
                };
                root.document.documentElement.appendChild(scriptElement);
                return id;
            };

        } else {
            scheduleMethod = function (action) {
                var id = nextHandle++;
                tasksByHandle[id] = action;
                localSetTimeout(function () {
                    runTask(id);
                }, 0);

                return id;
            };
        }
    }());

    /**
     * Gets a scheduler that schedules work via a timed callback based upon platform.
     */
    var DefaultScheduler = (function (__super__) {
        inherits(DefaultScheduler, __super__);
        function DefaultScheduler() {
            __super__.call(this);
        }

        function scheduleAction(disposable, action, scheduler, state) {
            return function schedule() {
                disposable.setDisposable(Disposable._fixup(action(scheduler, state)));
            };
        }

        function ClearDisposable(id) {
            this._id = id;
            this.isDisposed = false;
        }

        ClearDisposable.prototype.dispose = function () {
            if (!this.isDisposed) {
                this.isDisposed = true;
                clearMethod(this._id);
            }
        };

        function LocalClearDisposable(id) {
            this._id = id;
            this.isDisposed = false;
        }

        LocalClearDisposable.prototype.dispose = function () {
            if (!this.isDisposed) {
                this.isDisposed = true;
                localClearTimeout(this._id);
            }
        };

        DefaultScheduler.prototype.schedule = function (state, action) {
            var disposable = new SingleAssignmentDisposable(),
                id = scheduleMethod(scheduleAction(disposable, action, this, state));
            return new BinaryDisposable(disposable, new ClearDisposable(id));
        };

        DefaultScheduler.prototype._scheduleFuture = function (state, dueTime, action) {
            if (dueTime === 0) { return this.schedule(state, action); }
            var disposable = new SingleAssignmentDisposable(),
                id = localSetTimeout(scheduleAction(disposable, action, this, state), dueTime);
            return new BinaryDisposable(disposable, new LocalClearDisposable(id));
        };

        function scheduleLongRunning(state, action, disposable) {
            return function () { action(state, disposable); };
        }

        DefaultScheduler.prototype.scheduleLongRunning = function (state, action) {
            var disposable = disposableCreate(noop);
            scheduleMethod(scheduleLongRunning(state, action, disposable));
            return disposable;
        };

        return DefaultScheduler;
    }(Scheduler));

    var defaultScheduler = Scheduler['default'] = Scheduler.async = new DefaultScheduler();

    function IndexedItem(id, value) {
        this.id = id;
        this.value = value;
    }

    IndexedItem.prototype.compareTo = function (other) {
        var c = this.value.compareTo(other.value);
        c === 0 && (c = this.id - other.id);
        return c;
    };

    var PriorityQueue = Rx.internals.PriorityQueue = function (capacity) {
        this.items = new Array(capacity);
        this.length = 0;
    };

    var priorityProto = PriorityQueue.prototype;
    priorityProto.isHigherPriority = function (left, right) {
        return this.items[left].compareTo(this.items[right]) < 0;
    };

    priorityProto.percolate = function (index) {
        if (index >= this.length || index < 0) { return; }
        var parent = index - 1 >> 1;
        if (parent < 0 || parent === index) { return; }
        if (this.isHigherPriority(index, parent)) {
            var temp = this.items[index];
            this.items[index] = this.items[parent];
            this.items[parent] = temp;
            this.percolate(parent);
        }
    };

    priorityProto.heapify = function (index) {
        +index || (index = 0);
        if (index >= this.length || index < 0) { return; }
        var left = 2 * index + 1,
            right = 2 * index + 2,
            first = index;
        if (left < this.length && this.isHigherPriority(left, first)) {
            first = left;
        }
        if (right < this.length && this.isHigherPriority(right, first)) {
            first = right;
        }
        if (first !== index) {
            var temp = this.items[index];
            this.items[index] = this.items[first];
            this.items[first] = temp;
            this.heapify(first);
        }
    };

    priorityProto.peek = function () { return this.items[0].value; };

    priorityProto.removeAt = function (index) {
        this.items[index] = this.items[--this.length];
        this.items[this.length] = undefined;
        this.heapify();
    };

    priorityProto.dequeue = function () {
        var result = this.peek();
        this.removeAt(0);
        return result;
    };

    priorityProto.enqueue = function (item) {
        var index = this.length++;
        this.items[index] = new IndexedItem(PriorityQueue.count++, item);
        this.percolate(index);
    };

    priorityProto.remove = function (item) {
        for (var i = 0; i < this.length; i++) {
            if (this.items[i].value === item) {
                this.removeAt(i);
                return true;
            }
        }
        return false;
    };
    PriorityQueue.count = 0;

    /**
     *  Represents a notification to an observer.
     */
    var Notification = Rx.Notification = (function () {
        function Notification() {

        }

        Notification.prototype._accept = function (onNext, onError, onCompleted) {
            throw new NotImplementedError();
        };

        Notification.prototype._acceptObserver = function (onNext, onError, onCompleted) {
            throw new NotImplementedError();
        };

        /**
         * Invokes the delegate corresponding to the notification or the observer's method corresponding to the notification and returns the produced result.
         * @param {Function | Observer} observerOrOnNext Function to invoke for an OnNext notification or Observer to invoke the notification on..
         * @param {Function} onError Function to invoke for an OnError notification.
         * @param {Function} onCompleted Function to invoke for an OnCompleted notification.
         * @returns {Any} Result produced by the observation.
         */
        Notification.prototype.accept = function (observerOrOnNext, onError, onCompleted) {
            return observerOrOnNext && typeof observerOrOnNext === 'object' ?
              this._acceptObserver(observerOrOnNext) :
              this._accept(observerOrOnNext, onError, onCompleted);
        };

        /**
         * Returns an observable sequence with a single notification.
         *
         * @memberOf Notifications
         * @param {Scheduler} [scheduler] Scheduler to send out the notification calls on.
         * @returns {Observable} The observable sequence that surfaces the behavior of the notification upon subscription.
         */
        Notification.prototype.toObservable = function (scheduler) {
            var self = this;
            isScheduler(scheduler) || (scheduler = immediateScheduler);
            return new AnonymousObservable(function (o) {
                return scheduler.schedule(self, function (_, notification) {
                    notification._acceptObserver(o);
                    notification.kind === 'N' && o.onCompleted();
                });
            });
        };

        return Notification;
    })();

    var OnNextNotification = (function (__super__) {
        inherits(OnNextNotification, __super__);
        function OnNextNotification(value) {
            this.value = value;
            this.kind = 'N';
        }

        OnNextNotification.prototype._accept = function (onNext) {
            return onNext(this.value);
        };

        OnNextNotification.prototype._acceptObserver = function (o) {
            return o.onNext(this.value);
        };

        OnNextNotification.prototype.toString = function () {
            return 'OnNext(' + this.value + ')';
        };

        return OnNextNotification;
    }(Notification));

    var OnErrorNotification = (function (__super__) {
        inherits(OnErrorNotification, __super__);
        function OnErrorNotification(error) {
            this.error = error;
            this.kind = 'E';
        }

        OnErrorNotification.prototype._accept = function (onNext, onError) {
            return onError(this.error);
        };

        OnErrorNotification.prototype._acceptObserver = function (o) {
            return o.onError(this.error);
        };

        OnErrorNotification.prototype.toString = function () {
            return 'OnError(' + this.error + ')';
        };

        return OnErrorNotification;
    }(Notification));

    var OnCompletedNotification = (function (__super__) {
        inherits(OnCompletedNotification, __super__);
        function OnCompletedNotification() {
            this.kind = 'C';
        }

        OnCompletedNotification.prototype._accept = function (onNext, onError, onCompleted) {
            return onCompleted();
        };

        OnCompletedNotification.prototype._acceptObserver = function (o) {
            return o.onCompleted();
        };

        OnCompletedNotification.prototype.toString = function () {
            return 'OnCompleted()';
        };

        return OnCompletedNotification;
    }(Notification));

    /**
     * Creates an object that represents an OnNext notification to an observer.
     * @param {Any} value The value contained in the notification.
     * @returns {Notification} The OnNext notification containing the value.
     */
    var notificationCreateOnNext = Notification.createOnNext = function (value) {
        return new OnNextNotification(value);
    };

    /**
     * Creates an object that represents an OnError notification to an observer.
     * @param {Any} error The exception contained in the notification.
     * @returns {Notification} The OnError notification containing the exception.
     */
    var notificationCreateOnError = Notification.createOnError = function (error) {
        return new OnErrorNotification(error);
    };

    /**
     * Creates an object that represents an OnCompleted notification to an observer.
     * @returns {Notification} The OnCompleted notification.
     */
    var notificationCreateOnCompleted = Notification.createOnCompleted = function () {
        return new OnCompletedNotification();
    };

    /**
     * Supports push-style iteration over an observable sequence.
     */
    var Observer = Rx.Observer = function () { };

    /**
     *  Creates an observer from the specified OnNext, along with optional OnError, and OnCompleted actions.
     * @param {Function} [onNext] Observer's OnNext action implementation.
     * @param {Function} [onError] Observer's OnError action implementation.
     * @param {Function} [onCompleted] Observer's OnCompleted action implementation.
     * @returns {Observer} The observer object implemented using the given actions.
     */
    var observerCreate = Observer.create = function (onNext, onError, onCompleted) {
        onNext || (onNext = noop);
        onError || (onError = defaultError);
        onCompleted || (onCompleted = noop);
        return new AnonymousObserver(onNext, onError, onCompleted);
    };

    /**
     * Abstract base class for implementations of the Observer class.
     * This base class enforces the grammar of observers where OnError and OnCompleted are terminal messages.
     */
    var AbstractObserver = Rx.internals.AbstractObserver = (function (__super__) {
        inherits(AbstractObserver, __super__);

        /**
         * Creates a new observer in a non-stopped state.
         */
        function AbstractObserver() {
            this.isStopped = false;
        }

        // Must be implemented by other observers
        AbstractObserver.prototype.next = notImplemented;
        AbstractObserver.prototype.error = notImplemented;
        AbstractObserver.prototype.completed = notImplemented;

        /**
         * Notifies the observer of a new element in the sequence.
         * @param {Any} value Next element in the sequence.
         */
        AbstractObserver.prototype.onNext = function (value) {
            !this.isStopped && this.next(value);
        };

        /**
         * Notifies the observer that an exception has occurred.
         * @param {Any} error The error that has occurred.
         */
        AbstractObserver.prototype.onError = function (error) {
            if (!this.isStopped) {
                this.isStopped = true;
                this.error(error);
            }
        };

        /**
         * Notifies the observer of the end of the sequence.
         */
        AbstractObserver.prototype.onCompleted = function () {
            if (!this.isStopped) {
                this.isStopped = true;
                this.completed();
            }
        };

        /**
         * Disposes the observer, causing it to transition to the stopped state.
         */
        AbstractObserver.prototype.dispose = function () { this.isStopped = true; };

        AbstractObserver.prototype.fail = function (e) {
            if (!this.isStopped) {
                this.isStopped = true;
                this.error(e);
                return true;
            }

            return false;
        };

        return AbstractObserver;
    }(Observer));

    /**
     * Class to create an Observer instance from delegate-based implementations of the on* methods.
     */
    var AnonymousObserver = Rx.AnonymousObserver = (function (__super__) {
        inherits(AnonymousObserver, __super__);

        /**
         * Creates an observer from the specified OnNext, OnError, and OnCompleted actions.
         * @param {Any} onNext Observer's OnNext action implementation.
         * @param {Any} onError Observer's OnError action implementation.
         * @param {Any} onCompleted Observer's OnCompleted action implementation.
         */
        function AnonymousObserver(onNext, onError, onCompleted) {
            __super__.call(this);
            this._onNext = onNext;
            this._onError = onError;
            this._onCompleted = onCompleted;
        }

        /**
         * Calls the onNext action.
         * @param {Any} value Next element in the sequence.
         */
        AnonymousObserver.prototype.next = function (value) {
            this._onNext(value);
        };

        /**
         * Calls the onError action.
         * @param {Any} error The error that has occurred.
         */
        AnonymousObserver.prototype.error = function (error) {
            this._onError(error);
        };

        /**
         *  Calls the onCompleted action.
         */
        AnonymousObserver.prototype.completed = function () {
            this._onCompleted();
        };

        return AnonymousObserver;
    }(AbstractObserver));

    var observableProto;

    /**
     * Represents a push-style collection.
     */
    var Observable = Rx.Observable = (function () {

        function makeSubscribe(self, subscribe) {
            return function (o) {
                var oldOnError = o.onError;
                o.onError = function (e) {
                    makeStackTraceLong(e, self);
                    oldOnError.call(o, e);
                };

                return subscribe.call(self, o);
            };
        }

        function Observable() {
            if (Rx.config.longStackSupport && hasStacks) {
                var oldSubscribe = this._subscribe;
                var e = tryCatch(thrower)(new Error()).e;
                this.stack = e.stack.substring(e.stack.indexOf('\n') + 1);
                this._subscribe = makeSubscribe(this, oldSubscribe);
            }
        }

        observableProto = Observable.prototype;

        /**
        * Determines whether the given object is an Observable
        * @param {Any} An object to determine whether it is an Observable
        * @returns {Boolean} true if an Observable, else false.
        */
        Observable.isObservable = function (o) {
            return o && isFunction(o.subscribe);
        };

        /**
         *  Subscribes an o to the observable sequence.
         *  @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence.
         *  @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence.
         *  @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence.
         *  @returns {Diposable} A disposable handling the subscriptions and unsubscriptions.
         */
        observableProto.subscribe = observableProto.forEach = function (oOrOnNext, onError, onCompleted) {
            return this._subscribe(typeof oOrOnNext === 'object' ?
                oOrOnNext :
              observerCreate(oOrOnNext, onError, onCompleted));
        };

        /**
         * Subscribes to the next value in the sequence with an optional "this" argument.
         * @param {Function} onNext The function to invoke on each element in the observable sequence.
         * @param {Any} [thisArg] Object to use as this when executing callback.
         * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
         */
        observableProto.subscribeOnNext = function (onNext, thisArg) {
            return this._subscribe(observerCreate(typeof thisArg !== 'undefined' ? function (x) { onNext.call(thisArg, x); } : onNext));
        };

        /**
         * Subscribes to an exceptional condition in the sequence with an optional "this" argument.
         * @param {Function} onError The function to invoke upon exceptional termination of the observable sequence.
         * @param {Any} [thisArg] Object to use as this when executing callback.
         * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
         */
        observableProto.subscribeOnError = function (onError, thisArg) {
            return this._subscribe(observerCreate(null, typeof thisArg !== 'undefined' ? function (e) { onError.call(thisArg, e); } : onError));
        };

        /**
         * Subscribes to the next value in the sequence with an optional "this" argument.
         * @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence.
         * @param {Any} [thisArg] Object to use as this when executing callback.
         * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
         */
        observableProto.subscribeOnCompleted = function (onCompleted, thisArg) {
            return this._subscribe(observerCreate(null, null, typeof thisArg !== 'undefined' ? function () { onCompleted.call(thisArg); } : onCompleted));
        };

        return Observable;
    })();

    var ScheduledObserver = Rx.internals.ScheduledObserver = (function (__super__) {
        inherits(ScheduledObserver, __super__);

        function ScheduledObserver(scheduler, observer) {
            __super__.call(this);
            this.scheduler = scheduler;
            this.observer = observer;
            this.isAcquired = false;
            this.hasFaulted = false;
            this.queue = [];
            this.disposable = new SerialDisposable();
        }

        function enqueueNext(observer, x) { return function () { observer.onNext(x); }; }
        function enqueueError(observer, e) { return function () { observer.onError(e); }; }
        function enqueueCompleted(observer) { return function () { observer.onCompleted(); }; }

        ScheduledObserver.prototype.next = function (x) {
            this.queue.push(enqueueNext(this.observer, x));
        };

        ScheduledObserver.prototype.error = function (e) {
            this.queue.push(enqueueError(this.observer, e));
        };

        ScheduledObserver.prototype.completed = function () {
            this.queue.push(enqueueCompleted(this.observer));
        };


        function scheduleMethod(state, recurse) {
            var work;
            if (state.queue.length > 0) {
                work = state.queue.shift();
            } else {
                state.isAcquired = false;
                return;
            }
            var res = tryCatch(work)();
            if (res === errorObj) {
                state.queue = [];
                state.hasFaulted = true;
                return thrower(res.e);
            }
            recurse(state);
        }

        ScheduledObserver.prototype.ensureActive = function () {
            var isOwner = false;
            if (!this.hasFaulted && this.queue.length > 0) {
                isOwner = !this.isAcquired;
                this.isAcquired = true;
            }
            isOwner &&
              this.disposable.setDisposable(this.scheduler.scheduleRecursive(this, scheduleMethod));
        };

        ScheduledObserver.prototype.dispose = function () {
            __super__.prototype.dispose.call(this);
            this.disposable.dispose();
        };

        return ScheduledObserver;
    }(AbstractObserver));

    var ObservableBase = Rx.ObservableBase = (function (__super__) {
        inherits(ObservableBase, __super__);

        function fixSubscriber(subscriber) {
            return subscriber && isFunction(subscriber.dispose) ? subscriber :
              isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty;
        }

        function setDisposable(s, state) {
            var ado = state[0], self = state[1];
            var sub = tryCatch(self.subscribeCore).call(self, ado);
            if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); }
            ado.setDisposable(fixSubscriber(sub));
        }

        function ObservableBase() {
            __super__.call(this);
        }

        ObservableBase.prototype._subscribe = function (o) {
            var ado = new AutoDetachObserver(o), state = [ado, this];

            if (currentThreadScheduler.scheduleRequired()) {
                currentThreadScheduler.schedule(state, setDisposable);
            } else {
                setDisposable(null, state);
            }
            return ado;
        };

        ObservableBase.prototype.subscribeCore = notImplemented;

        return ObservableBase;
    }(Observable));

    var FlatMapObservable = Rx.FlatMapObservable = (function (__super__) {

        inherits(FlatMapObservable, __super__);

        function FlatMapObservable(source, selector, resultSelector, thisArg) {
            this.resultSelector = isFunction(resultSelector) ? resultSelector : null;
            this.selector = bindCallback(isFunction(selector) ? selector : function () { return selector; }, thisArg, 3);
            this.source = source;
            __super__.call(this);
        }

        FlatMapObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o, this.selector, this.resultSelector, this));
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(observer, selector, resultSelector, source) {
            this.i = 0;
            this.selector = selector;
            this.resultSelector = resultSelector;
            this.source = source;
            this.o = observer;
            AbstractObserver.call(this);
        }

        InnerObserver.prototype._wrapResult = function (result, x, i) {
            return this.resultSelector ?
              result.map(function (y, i2) { return this.resultSelector(x, y, i, i2); }, this) :
              result;
        };

        InnerObserver.prototype.next = function (x) {
            var i = this.i++;
            var result = tryCatch(this.selector)(x, i, this.source);
            if (result === errorObj) { return this.o.onError(result.e); }

            isPromise(result) && (result = observableFromPromise(result));
            (isArrayLike(result) || isIterable(result)) && (result = Observable.from(result));
            this.o.onNext(this._wrapResult(result, x, i));
        };

        InnerObserver.prototype.error = function (e) { this.o.onError(e); };

        InnerObserver.prototype.completed = function () { this.o.onCompleted(); };

        return FlatMapObservable;

    }(ObservableBase));

    var Enumerable = Rx.internals.Enumerable = function () { };

    function IsDisposedDisposable(state) {
        this._s = state;
        this.isDisposed = false;
    }

    IsDisposedDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this.isDisposed = true;
            this._s.isDisposed = true;
        }
    };

    var ConcatEnumerableObservable = (function (__super__) {
        inherits(ConcatEnumerableObservable, __super__);
        function ConcatEnumerableObservable(sources) {
            this.sources = sources;
            __super__.call(this);
        }

        function scheduleMethod(state, recurse) {
            if (state.isDisposed) { return; }
            var currentItem = tryCatch(state.e.next).call(state.e);
            if (currentItem === errorObj) { return state.o.onError(currentItem.e); }
            if (currentItem.done) { return state.o.onCompleted(); }

            // Check if promise
            var currentValue = currentItem.value;
            isPromise(currentValue) && (currentValue = observableFromPromise(currentValue));

            var d = new SingleAssignmentDisposable();
            state.subscription.setDisposable(d);
            d.setDisposable(currentValue.subscribe(new InnerObserver(state, recurse)));
        }

        ConcatEnumerableObservable.prototype.subscribeCore = function (o) {
            var subscription = new SerialDisposable();
            var state = {
                isDisposed: false,
                o: o,
                subscription: subscription,
                e: this.sources[$iterator$]()
            };

            var cancelable = currentThreadScheduler.scheduleRecursive(state, scheduleMethod);
            return new NAryDisposable([subscription, cancelable, new IsDisposedDisposable(state)]);
        };

        function InnerObserver(state, recurse) {
            this._state = state;
            this._recurse = recurse;
            AbstractObserver.call(this);
        }

        inherits(InnerObserver, AbstractObserver);

        InnerObserver.prototype.next = function (x) { this._state.o.onNext(x); };
        InnerObserver.prototype.error = function (e) { this._state.o.onError(e); };
        InnerObserver.prototype.completed = function () { this._recurse(this._state); };

        return ConcatEnumerableObservable;
    }(ObservableBase));

    Enumerable.prototype.concat = function () {
        return new ConcatEnumerableObservable(this);
    };

    var CatchErrorObservable = (function (__super__) {
        function CatchErrorObservable(sources) {
            this.sources = sources;
            __super__.call(this);
        }

        inherits(CatchErrorObservable, __super__);

        function scheduleMethod(state, recurse) {
            if (state.isDisposed) { return; }
            var currentItem = tryCatch(state.e.next).call(state.e);
            if (currentItem === errorObj) { return state.o.onError(currentItem.e); }
            if (currentItem.done) { return state.lastError !== null ? state.o.onError(state.lastError) : state.o.onCompleted(); }

            var currentValue = currentItem.value;
            isPromise(currentValue) && (currentValue = observableFromPromise(currentValue));

            var d = new SingleAssignmentDisposable();
            state.subscription.setDisposable(d);
            d.setDisposable(currentValue.subscribe(new InnerObserver(state, recurse)));
        }

        CatchErrorObservable.prototype.subscribeCore = function (o) {
            var subscription = new SerialDisposable();
            var state = {
                isDisposed: false,
                e: this.sources[$iterator$](),
                subscription: subscription,
                lastError: null,
                o: o
            };

            var cancelable = currentThreadScheduler.scheduleRecursive(state, scheduleMethod);
            return new NAryDisposable([subscription, cancelable, new IsDisposedDisposable(state)]);
        };

        function InnerObserver(state, recurse) {
            this._state = state;
            this._recurse = recurse;
            AbstractObserver.call(this);
        }

        inherits(InnerObserver, AbstractObserver);

        InnerObserver.prototype.next = function (x) { this._state.o.onNext(x); };
        InnerObserver.prototype.error = function (e) { this._state.lastError = e; this._recurse(this._state); };
        InnerObserver.prototype.completed = function () { this._state.o.onCompleted(); };

        return CatchErrorObservable;
    }(ObservableBase));

    Enumerable.prototype.catchError = function () {
        return new CatchErrorObservable(this);
    };

    var RepeatEnumerable = (function (__super__) {
        inherits(RepeatEnumerable, __super__);
        function RepeatEnumerable(v, c) {
            this.v = v;
            this.c = c == null ? -1 : c;
        }

        RepeatEnumerable.prototype[$iterator$] = function () {
            return new RepeatEnumerator(this);
        };

        function RepeatEnumerator(p) {
            this.v = p.v;
            this.l = p.c;
        }

        RepeatEnumerator.prototype.next = function () {
            if (this.l === 0) { return doneEnumerator; }
            if (this.l > 0) { this.l--; }
            return { done: false, value: this.v };
        };

        return RepeatEnumerable;
    }(Enumerable));

    var enumerableRepeat = Enumerable.repeat = function (value, repeatCount) {
        return new RepeatEnumerable(value, repeatCount);
    };

    var OfEnumerable = (function (__super__) {
        inherits(OfEnumerable, __super__);
        function OfEnumerable(s, fn, thisArg) {
            this.s = s;
            this.fn = fn ? bindCallback(fn, thisArg, 3) : null;
        }
        OfEnumerable.prototype[$iterator$] = function () {
            return new OfEnumerator(this);
        };

        function OfEnumerator(p) {
            this.i = -1;
            this.s = p.s;
            this.l = this.s.length;
            this.fn = p.fn;
        }

        OfEnumerator.prototype.next = function () {
            return ++this.i < this.l ?
       { done: false, value: !this.fn ? this.s[this.i] : this.fn(this.s[this.i], this.i, this.s) } :
              doneEnumerator;
        };

        return OfEnumerable;
    }(Enumerable));

    var enumerableOf = Enumerable.of = function (source, selector, thisArg) {
        return new OfEnumerable(source, selector, thisArg);
    };

    var ToArrayObservable = (function (__super__) {
        inherits(ToArrayObservable, __super__);
        function ToArrayObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        ToArrayObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o));
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(o) {
            this.o = o;
            this.a = [];
            AbstractObserver.call(this);
        }

        InnerObserver.prototype.next = function (x) { this.a.push(x); };
        InnerObserver.prototype.error = function (e) { this.o.onError(e); };
        InnerObserver.prototype.completed = function () { this.o.onNext(this.a); this.o.onCompleted(); };

        return ToArrayObservable;
    }(ObservableBase));

    /**
    * Creates an array from an observable sequence.
    * @returns {Observable} An observable sequence containing a single element with a list containing all the elements of the source sequence.
    */
    observableProto.toArray = function () {
        return new ToArrayObservable(this);
    };

    /**
     *  Creates an observable sequence from a specified subscribe method implementation.
     * @example
     *  var res = Rx.Observable.create(function (observer) { return function () { } );
     *  var res = Rx.Observable.create(function (observer) { return Rx.Disposable.empty; } );
     *  var res = Rx.Observable.create(function (observer) { } );
     * @param {Function} subscribe Implementation of the resulting observable sequence's subscribe method, returning a function that will be wrapped in a Disposable.
     * @returns {Observable} The observable sequence with the specified implementation for the Subscribe method.
     */
    Observable.create = function (subscribe, parent) {
        return new AnonymousObservable(subscribe, parent);
    };

    var Defer = (function (__super__) {
        inherits(Defer, __super__);
        function Defer(factory) {
            this._f = factory;
            __super__.call(this);
        }

        Defer.prototype.subscribeCore = function (o) {
            var result = tryCatch(this._f)();
            if (result === errorObj) { return observableThrow(result.e).subscribe(o); }
            isPromise(result) && (result = observableFromPromise(result));
            return result.subscribe(o);
        };

        return Defer;
    }(ObservableBase));

    /**
     *  Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes.
     *
     * @example
     *  var res = Rx.Observable.defer(function () { return Rx.Observable.fromArray([1,2,3]); });
     * @param {Function} observableFactory Observable factory function to invoke for each observer that subscribes to the resulting sequence or Promise.
     * @returns {Observable} An observable sequence whose observers trigger an invocation of the given observable factory function.
     */
    var observableDefer = Observable.defer = function (observableFactory) {
        return new Defer(observableFactory);
    };

    var EmptyObservable = (function (__super__) {
        inherits(EmptyObservable, __super__);
        function EmptyObservable(scheduler) {
            this.scheduler = scheduler;
            __super__.call(this);
        }

        EmptyObservable.prototype.subscribeCore = function (observer) {
            var sink = new EmptySink(observer, this.scheduler);
            return sink.run();
        };

        function EmptySink(observer, scheduler) {
            this.observer = observer;
            this.scheduler = scheduler;
        }

        function scheduleItem(s, state) {
            state.onCompleted();
            return disposableEmpty;
        }

        EmptySink.prototype.run = function () {
            var state = this.observer;
            return this.scheduler === immediateScheduler ?
              scheduleItem(null, state) :
              this.scheduler.schedule(state, scheduleItem);
        };

        return EmptyObservable;
    }(ObservableBase));

    var EMPTY_OBSERVABLE = new EmptyObservable(immediateScheduler);

    /**
     *  Returns an empty observable sequence, using the specified scheduler to send out the single OnCompleted message.
     *
     * @example
     *  var res = Rx.Observable.empty();
     *  var res = Rx.Observable.empty(Rx.Scheduler.timeout);
     * @param {Scheduler} [scheduler] Scheduler to send the termination call on.
     * @returns {Observable} An observable sequence with no elements.
     */
    var observableEmpty = Observable.empty = function (scheduler) {
        isScheduler(scheduler) || (scheduler = immediateScheduler);
        return scheduler === immediateScheduler ? EMPTY_OBSERVABLE : new EmptyObservable(scheduler);
    };

    var FromObservable = (function (__super__) {
        inherits(FromObservable, __super__);
        function FromObservable(iterable, fn, scheduler) {
            this._iterable = iterable;
            this._fn = fn;
            this._scheduler = scheduler;
            __super__.call(this);
        }

        function createScheduleMethod(o, it, fn) {
            return function loopRecursive(i, recurse) {
                var next = tryCatch(it.next).call(it);
                if (next === errorObj) { return o.onError(next.e); }
                if (next.done) { return o.onCompleted(); }

                var result = next.value;

                if (isFunction(fn)) {
                    result = tryCatch(fn)(result, i);
                    if (result === errorObj) { return o.onError(result.e); }
                }

                o.onNext(result);
                recurse(i + 1);
            };
        }

        FromObservable.prototype.subscribeCore = function (o) {
            var list = Object(this._iterable),
                it = getIterable(list);

            return this._scheduler.scheduleRecursive(0, createScheduleMethod(o, it, this._fn));
        };

        return FromObservable;
    }(ObservableBase));

    var maxSafeInteger = Math.pow(2, 53) - 1;

    function StringIterable(s) {
        this._s = s;
    }

    StringIterable.prototype[$iterator$] = function () {
        return new StringIterator(this._s);
    };

    function StringIterator(s) {
        this._s = s;
        this._l = s.length;
        this._i = 0;
    }

    StringIterator.prototype[$iterator$] = function () {
        return this;
    };

    StringIterator.prototype.next = function () {
        return this._i < this._l ? { done: false, value: this._s.charAt(this._i++) } : doneEnumerator;
    };

    function ArrayIterable(a) {
        this._a = a;
    }

    ArrayIterable.prototype[$iterator$] = function () {
        return new ArrayIterator(this._a);
    };

    function ArrayIterator(a) {
        this._a = a;
        this._l = toLength(a);
        this._i = 0;
    }

    ArrayIterator.prototype[$iterator$] = function () {
        return this;
    };

    ArrayIterator.prototype.next = function () {
        return this._i < this._l ? { done: false, value: this._a[this._i++] } : doneEnumerator;
    };

    function numberIsFinite(value) {
        return typeof value === 'number' && root.isFinite(value);
    }

    function isNan(n) {
        return n !== n;
    }

    function getIterable(o) {
        var i = o[$iterator$], it;
        if (!i && typeof o === 'string') {
            it = new StringIterable(o);
            return it[$iterator$]();
        }
        if (!i && o.length !== undefined) {
            it = new ArrayIterable(o);
            return it[$iterator$]();
        }
        if (!i) { throw new TypeError('Object is not iterable'); }
        return o[$iterator$]();
    }

    function sign(value) {
        var number = +value;
        if (number === 0) { return number; }
        if (isNaN(number)) { return number; }
        return number < 0 ? -1 : 1;
    }

    function toLength(o) {
        var len = +o.length;
        if (isNaN(len)) { return 0; }
        if (len === 0 || !numberIsFinite(len)) { return len; }
        len = sign(len) * Math.floor(Math.abs(len));
        if (len <= 0) { return 0; }
        if (len > maxSafeInteger) { return maxSafeInteger; }
        return len;
    }

    /**
    * This method creates a new Observable sequence from an array-like or iterable object.
    * @param {Any} arrayLike An array-like or iterable object to convert to an Observable sequence.
    * @param {Function} [mapFn] Map function to call on every element of the array.
    * @param {Any} [thisArg] The context to use calling the mapFn if provided.
    * @param {Scheduler} [scheduler] Optional scheduler to use for scheduling.  If not provided, defaults to Scheduler.currentThread.
    */
    var observableFrom = Observable.from = function (iterable, mapFn, thisArg, scheduler) {
        if (iterable == null) {
            throw new Error('iterable cannot be null.')
        }
        if (mapFn && !isFunction(mapFn)) {
            throw new Error('mapFn when provided must be a function');
        }
        if (mapFn) {
            var mapper = bindCallback(mapFn, thisArg, 2);
        }
        isScheduler(scheduler) || (scheduler = currentThreadScheduler);
        return new FromObservable(iterable, mapper, scheduler);
    }

    var FromArrayObservable = (function (__super__) {
        inherits(FromArrayObservable, __super__);
        function FromArrayObservable(args, scheduler) {
            this._args = args;
            this._scheduler = scheduler;
            __super__.call(this);
        }

        function scheduleMethod(o, args) {
            var len = args.length;
            return function loopRecursive(i, recurse) {
                if (i < len) {
                    o.onNext(args[i]);
                    recurse(i + 1);
                } else {
                    o.onCompleted();
                }
            };
        }

        FromArrayObservable.prototype.subscribeCore = function (o) {
            return this._scheduler.scheduleRecursive(0, scheduleMethod(o, this._args));
        };

        return FromArrayObservable;
    }(ObservableBase));

    /**
    *  Converts an array to an observable sequence, using an optional scheduler to enumerate the array.
    * @deprecated use Observable.from or Observable.of
    * @param {Scheduler} [scheduler] Scheduler to run the enumeration of the input sequence on.
    * @returns {Observable} The observable sequence whose elements are pulled from the given enumerable sequence.
    */
    var observableFromArray = Observable.fromArray = function (array, scheduler) {
        isScheduler(scheduler) || (scheduler = currentThreadScheduler);
        return new FromArrayObservable(array, scheduler)
    };

    var NeverObservable = (function (__super__) {
        inherits(NeverObservable, __super__);
        function NeverObservable() {
            __super__.call(this);
        }

        NeverObservable.prototype.subscribeCore = function (observer) {
            return disposableEmpty;
        };

        return NeverObservable;
    }(ObservableBase));

    var NEVER_OBSERVABLE = new NeverObservable();

    /**
     * Returns a non-terminating observable sequence, which can be used to denote an infinite duration (e.g. when using reactive joins).
     * @returns {Observable} An observable sequence whose observers will never get called.
     */
    var observableNever = Observable.never = function () {
        return NEVER_OBSERVABLE;
    };

    function observableOf(scheduler, array) {
        isScheduler(scheduler) || (scheduler = currentThreadScheduler);
        return new FromArrayObservable(array, scheduler);
    }

    /**
    *  This method creates a new Observable instance with a variable number of arguments, regardless of number or type of the arguments.
    * @returns {Observable} The observable sequence whose elements are pulled from the given arguments.
    */
    Observable.of = function () {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        return new FromArrayObservable(args, currentThreadScheduler);
    };

    /**
    *  This method creates a new Observable instance with a variable number of arguments, regardless of number or type of the arguments.
    * @param {Scheduler} scheduler A scheduler to use for scheduling the arguments.
    * @returns {Observable} The observable sequence whose elements are pulled from the given arguments.
    */
    Observable.ofWithScheduler = function (scheduler) {
        var len = arguments.length, args = new Array(len - 1);
        for (var i = 1; i < len; i++) { args[i - 1] = arguments[i]; }
        return new FromArrayObservable(args, scheduler);
    };

    var PairsObservable = (function (__super__) {
        inherits(PairsObservable, __super__);
        function PairsObservable(o, scheduler) {
            this._o = o;
            this._keys = Object.keys(o);
            this._scheduler = scheduler;
            __super__.call(this);
        }

        function scheduleMethod(o, obj, keys) {
            return function loopRecursive(i, recurse) {
                if (i < keys.length) {
                    var key = keys[i];
                    o.onNext([key, obj[key]]);
                    recurse(i + 1);
                } else {
                    o.onCompleted();
                }
            };
        }

        PairsObservable.prototype.subscribeCore = function (o) {
            return this._scheduler.scheduleRecursive(0, scheduleMethod(o, this._o, this._keys));
        };

        return PairsObservable;
    }(ObservableBase));

    /**
     * Convert an object into an observable sequence of [key, value] pairs.
     * @param {Object} obj The object to inspect.
     * @param {Scheduler} [scheduler] Scheduler to run the enumeration of the input sequence on.
     * @returns {Observable} An observable sequence of [key, value] pairs from the object.
     */
    Observable.pairs = function (obj, scheduler) {
        scheduler || (scheduler = currentThreadScheduler);
        return new PairsObservable(obj, scheduler);
    };

    var RangeObservable = (function (__super__) {
        inherits(RangeObservable, __super__);
        function RangeObservable(start, count, scheduler) {
            this.start = start;
            this.rangeCount = count;
            this.scheduler = scheduler;
            __super__.call(this);
        }

        function loopRecursive(start, count, o) {
            return function loop(i, recurse) {
                if (i < count) {
                    o.onNext(start + i);
                    recurse(i + 1);
                } else {
                    o.onCompleted();
                }
            };
        }

        RangeObservable.prototype.subscribeCore = function (o) {
            return this.scheduler.scheduleRecursive(
              0,
              loopRecursive(this.start, this.rangeCount, o)
            );
        };

        return RangeObservable;
    }(ObservableBase));

    /**
    *  Generates an observable sequence of integral numbers within a specified range, using the specified scheduler to send out observer messages.
    * @param {Number} start The value of the first integer in the sequence.
    * @param {Number} count The number of sequential integers to generate.
    * @param {Scheduler} [scheduler] Scheduler to run the generator loop on. If not specified, defaults to Scheduler.currentThread.
    * @returns {Observable} An observable sequence that contains a range of sequential integral numbers.
    */
    Observable.range = function (start, count, scheduler) {
        isScheduler(scheduler) || (scheduler = currentThreadScheduler);
        return new RangeObservable(start, count, scheduler);
    };

    var RepeatObservable = (function (__super__) {
        inherits(RepeatObservable, __super__);
        function RepeatObservable(value, repeatCount, scheduler) {
            this.value = value;
            this.repeatCount = repeatCount == null ? -1 : repeatCount;
            this.scheduler = scheduler;
            __super__.call(this);
        }

        RepeatObservable.prototype.subscribeCore = function (observer) {
            var sink = new RepeatSink(observer, this);
            return sink.run();
        };

        return RepeatObservable;
    }(ObservableBase));

    function RepeatSink(observer, parent) {
        this.observer = observer;
        this.parent = parent;
    }

    RepeatSink.prototype.run = function () {
        var observer = this.observer, value = this.parent.value;
        function loopRecursive(i, recurse) {
            if (i === -1 || i > 0) {
                observer.onNext(value);
                i > 0 && i--;
            }
            if (i === 0) { return observer.onCompleted(); }
            recurse(i);
        }

        return this.parent.scheduler.scheduleRecursive(this.parent.repeatCount, loopRecursive);
    };

    /**
     *  Generates an observable sequence that repeats the given element the specified number of times, using the specified scheduler to send out observer messages.
     * @param {Mixed} value Element to repeat.
     * @param {Number} repeatCount [Optiona] Number of times to repeat the element. If not specified, repeats indefinitely.
     * @param {Scheduler} scheduler Scheduler to run the producer loop on. If not specified, defaults to Scheduler.immediate.
     * @returns {Observable} An observable sequence that repeats the given element the specified number of times.
     */
    Observable.repeat = function (value, repeatCount, scheduler) {
        isScheduler(scheduler) || (scheduler = currentThreadScheduler);
        return new RepeatObservable(value, repeatCount, scheduler);
    };

    var JustObservable = (function (__super__) {
        inherits(JustObservable, __super__);
        function JustObservable(value, scheduler) {
            this._value = value;
            this._scheduler = scheduler;
            __super__.call(this);
        }

        JustObservable.prototype.subscribeCore = function (o) {
            var state = [this._value, o];
            return this._scheduler === immediateScheduler ?
              scheduleItem(null, state) :
              this._scheduler.schedule(state, scheduleItem);
        };

        function scheduleItem(s, state) {
            var value = state[0], observer = state[1];
            observer.onNext(value);
            observer.onCompleted();
            return disposableEmpty;
        }

        return JustObservable;
    }(ObservableBase));

    /**
     *  Returns an observable sequence that contains a single element, using the specified scheduler to send out observer messages.
     *  There is an alias called 'just' or browsers <IE9.
     * @param {Mixed} value Single element in the resulting observable sequence.
     * @param {Scheduler} scheduler Scheduler to send the single element on. If not specified, defaults to Scheduler.immediate.
     * @returns {Observable} An observable sequence containing the single specified element.
     */
    var observableReturn = Observable['return'] = Observable.just = function (value, scheduler) {
        isScheduler(scheduler) || (scheduler = immediateScheduler);
        return new JustObservable(value, scheduler);
    };

    var ThrowObservable = (function (__super__) {
        inherits(ThrowObservable, __super__);
        function ThrowObservable(error, scheduler) {
            this._error = error;
            this._scheduler = scheduler;
            __super__.call(this);
        }

        ThrowObservable.prototype.subscribeCore = function (o) {
            var state = [this._error, o];
            return this._scheduler === immediateScheduler ?
              scheduleItem(null, state) :
              this._scheduler.schedule(state, scheduleItem);
        };

        function scheduleItem(s, state) {
            var e = state[0], o = state[1];
            o.onError(e);
            return disposableEmpty;
        }

        return ThrowObservable;
    }(ObservableBase));

    /**
     *  Returns an observable sequence that terminates with an exception, using the specified scheduler to send out the single onError message.
     *  There is an alias to this method called 'throwError' for browsers <IE9.
     * @param {Mixed} error An object used for the sequence's termination.
     * @param {Scheduler} scheduler Scheduler to send the exceptional termination call on. If not specified, defaults to Scheduler.immediate.
     * @returns {Observable} The observable sequence that terminates exceptionally with the specified exception object.
     */
    var observableThrow = Observable['throw'] = function (error, scheduler) {
        isScheduler(scheduler) || (scheduler = immediateScheduler);
        return new ThrowObservable(error, scheduler);
    };

    var CatchObservable = (function (__super__) {
        inherits(CatchObservable, __super__);
        function CatchObservable(source, fn) {
            this.source = source;
            this._fn = fn;
            __super__.call(this);
        }

        CatchObservable.prototype.subscribeCore = function (o) {
            var d1 = new SingleAssignmentDisposable(), subscription = new SerialDisposable();
            subscription.setDisposable(d1);
            d1.setDisposable(this.source.subscribe(new CatchObserver(o, subscription, this._fn)));
            return subscription;
        };

        return CatchObservable;
    }(ObservableBase));

    var CatchObserver = (function (__super__) {
        inherits(CatchObserver, __super__);
        function CatchObserver(o, s, fn) {
            this._o = o;
            this._s = s;
            this._fn = fn;
            __super__.call(this);
        }

        CatchObserver.prototype.next = function (x) { this._o.onNext(x); };
        CatchObserver.prototype.completed = function () { return this._o.onCompleted(); };
        CatchObserver.prototype.error = function (e) {
            var result = tryCatch(this._fn)(e);
            if (result === errorObj) { return this._o.onError(result.e); }
            isPromise(result) && (result = observableFromPromise(result));

            var d = new SingleAssignmentDisposable();
            this._s.setDisposable(d);
            d.setDisposable(result.subscribe(this._o));
        };

        return CatchObserver;
    }(AbstractObserver));

    /**
     * Continues an observable sequence that is terminated by an exception with the next observable sequence.
     * @param {Mixed} handlerOrSecond Exception handler function that returns an observable sequence given the error that occurred in the first sequence, or a second observable sequence used to produce results when an error occurred in the first sequence.
     * @returns {Observable} An observable sequence containing the first sequence's elements, followed by the elements of the handler sequence in case an exception occurred.
     */
    observableProto['catch'] = function (handlerOrSecond) {
        return isFunction(handlerOrSecond) ? new CatchObservable(this, handlerOrSecond) : observableCatch([this, handlerOrSecond]);
    };

    /**
     * Continues an observable sequence that is terminated by an exception with the next observable sequence.
     * @param {Array | Arguments} args Arguments or an array to use as the next sequence if an error occurs.
     * @returns {Observable} An observable sequence containing elements from consecutive source sequences until a source sequence terminates successfully.
     */
    var observableCatch = Observable['catch'] = function () {
        var items;
        if (Array.isArray(arguments[0])) {
            items = arguments[0];
        } else {
            var len = arguments.length;
            items = new Array(len);
            for (var i = 0; i < len; i++) { items[i] = arguments[i]; }
        }
        return enumerableOf(items).catchError();
    };

    /**
     * Merges the specified observable sequences into one observable sequence by using the selector function whenever any of the observable sequences or Promises produces an element.
     * This can be in the form of an argument list of observables or an array.
     *
     * @example
     * 1 - obs = observable.combineLatest(obs1, obs2, obs3, function (o1, o2, o3) { return o1 + o2 + o3; });
     * 2 - obs = observable.combineLatest([obs1, obs2, obs3], function (o1, o2, o3) { return o1 + o2 + o3; });
     * @returns {Observable} An observable sequence containing the result of combining elements of the sources using the specified result selector function.
     */
    observableProto.combineLatest = function () {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        if (Array.isArray(args[0])) {
            args[0].unshift(this);
        } else {
            args.unshift(this);
        }
        return combineLatest.apply(this, args);
    };

    function falseFactory() { return false; }
    function argumentsToArray() {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        return args;
    }

    var CombineLatestObservable = (function (__super__) {
        inherits(CombineLatestObservable, __super__);
        function CombineLatestObservable(params, cb) {
            this._params = params;
            this._cb = cb;
            __super__.call(this);
        }

        CombineLatestObservable.prototype.subscribeCore = function (observer) {
            var len = this._params.length,
                subscriptions = new Array(len);

            var state = {
                hasValue: arrayInitialize(len, falseFactory),
                hasValueAll: false,
                isDone: arrayInitialize(len, falseFactory),
                values: new Array(len)
            };

            for (var i = 0; i < len; i++) {
                var source = this._params[i], sad = new SingleAssignmentDisposable();
                subscriptions[i] = sad;
                isPromise(source) && (source = observableFromPromise(source));
                sad.setDisposable(source.subscribe(new CombineLatestObserver(observer, i, this._cb, state)));
            }

            return new NAryDisposable(subscriptions);
        };

        return CombineLatestObservable;
    }(ObservableBase));

    var CombineLatestObserver = (function (__super__) {
        inherits(CombineLatestObserver, __super__);
        function CombineLatestObserver(o, i, cb, state) {
            this._o = o;
            this._i = i;
            this._cb = cb;
            this._state = state;
            __super__.call(this);
        }

        function notTheSame(i) {
            return function (x, j) {
                return j !== i;
            };
        }

        CombineLatestObserver.prototype.next = function (x) {
            this._state.values[this._i] = x;
            this._state.hasValue[this._i] = true;
            if (this._state.hasValueAll || (this._state.hasValueAll = this._state.hasValue.every(identity))) {
                var res = tryCatch(this._cb).apply(null, this._state.values);
                if (res === errorObj) { return this._o.onError(res.e); }
                this._o.onNext(res);
            } else if (this._state.isDone.filter(notTheSame(this._i)).every(identity)) {
                this._o.onCompleted();
            }
        };

        CombineLatestObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        CombineLatestObserver.prototype.completed = function () {
            this._state.isDone[this._i] = true;
            this._state.isDone.every(identity) && this._o.onCompleted();
        };

        return CombineLatestObserver;
    }(AbstractObserver));

    /**
    * Merges the specified observable sequences into one observable sequence by using the selector function whenever any of the observable sequences or Promises produces an element.
    *
    * @example
    * 1 - obs = Rx.Observable.combineLatest(obs1, obs2, obs3, function (o1, o2, o3) { return o1 + o2 + o3; });
    * 2 - obs = Rx.Observable.combineLatest([obs1, obs2, obs3], function (o1, o2, o3) { return o1 + o2 + o3; });
    * @returns {Observable} An observable sequence containing the result of combining elements of the sources using the specified result selector function.
    */
    var combineLatest = Observable.combineLatest = function () {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        var resultSelector = isFunction(args[len - 1]) ? args.pop() : argumentsToArray;
        Array.isArray(args[0]) && (args = args[0]);
        return new CombineLatestObservable(args, resultSelector);
    };

    /**
     * Concatenates all the observable sequences.  This takes in either an array or variable arguments to concatenate.
     * @returns {Observable} An observable sequence that contains the elements of each given sequence, in sequential order.
     */
    observableProto.concat = function () {
        for (var args = [], i = 0, len = arguments.length; i < len; i++) { args.push(arguments[i]); }
        args.unshift(this);
        return observableConcat.apply(null, args);
    };

    var ConcatObserver = (function (__super__) {
        inherits(ConcatObserver, __super__);
        function ConcatObserver(s, fn) {
            this._s = s;
            this._fn = fn;
            __super__.call(this);
        }

        ConcatObserver.prototype.next = function (x) { this._s.o.onNext(x); };
        ConcatObserver.prototype.error = function (e) { this._s.o.onError(e); };
        ConcatObserver.prototype.completed = function () { this._s.i++; this._fn(this._s); };

        return ConcatObserver;
    }(AbstractObserver));

    var ConcatObservable = (function (__super__) {
        inherits(ConcatObservable, __super__);
        function ConcatObservable(sources) {
            this._sources = sources;
            __super__.call(this);
        }

        function scheduleRecursive(state, recurse) {
            if (state.disposable.isDisposed) { return; }
            if (state.i === state.sources.length) { return state.o.onCompleted(); }

            // Check if promise
            var currentValue = state.sources[state.i];
            isPromise(currentValue) && (currentValue = observableFromPromise(currentValue));

            var d = new SingleAssignmentDisposable();
            state.subscription.setDisposable(d);
            d.setDisposable(currentValue.subscribe(new ConcatObserver(state, recurse)));
        }

        ConcatObservable.prototype.subscribeCore = function (o) {
            var subscription = new SerialDisposable();
            var disposable = disposableCreate(noop);
            var state = {
                o: o,
                i: 0,
                subscription: subscription,
                disposable: disposable,
                sources: this._sources
            };

            var cancelable = immediateScheduler.scheduleRecursive(state, scheduleRecursive);
            return new NAryDisposable([subscription, disposable, cancelable]);
        };

        return ConcatObservable;
    }(ObservableBase));

    /**
     * Concatenates all the observable sequences.
     * @param {Array | Arguments} args Arguments or an array to concat to the observable sequence.
     * @returns {Observable} An observable sequence that contains the elements of each given sequence, in sequential order.
     */
    var observableConcat = Observable.concat = function () {
        var args;
        if (Array.isArray(arguments[0])) {
            args = arguments[0];
        } else {
            args = new Array(arguments.length);
            for (var i = 0, len = arguments.length; i < len; i++) { args[i] = arguments[i]; }
        }
        return new ConcatObservable(args);
    };

    /**
     * Concatenates an observable sequence of observable sequences.
     * @returns {Observable} An observable sequence that contains the elements of each observed inner sequence, in sequential order.
     */
    observableProto.concatAll = function () {
        return this.merge(1);
    };

    var MergeObservable = (function (__super__) {
        inherits(MergeObservable, __super__);

        function MergeObservable(source, maxConcurrent) {
            this.source = source;
            this.maxConcurrent = maxConcurrent;
            __super__.call(this);
        }

        MergeObservable.prototype.subscribeCore = function (observer) {
            var g = new CompositeDisposable();
            g.add(this.source.subscribe(new MergeObserver(observer, this.maxConcurrent, g)));
            return g;
        };

        return MergeObservable;

    }(ObservableBase));

    var MergeObserver = (function (__super__) {
        function MergeObserver(o, max, g) {
            this.o = o;
            this.max = max;
            this.g = g;
            this.done = false;
            this.q = [];
            this.activeCount = 0;
            __super__.call(this);
        }

        inherits(MergeObserver, __super__);

        MergeObserver.prototype.handleSubscribe = function (xs) {
            var sad = new SingleAssignmentDisposable();
            this.g.add(sad);
            isPromise(xs) && (xs = observableFromPromise(xs));
            sad.setDisposable(xs.subscribe(new InnerObserver(this, sad)));
        };

        MergeObserver.prototype.next = function (innerSource) {
            if (this.activeCount < this.max) {
                this.activeCount++;
                this.handleSubscribe(innerSource);
            } else {
                this.q.push(innerSource);
            }
        };
        MergeObserver.prototype.error = function (e) { this.o.onError(e); };
        MergeObserver.prototype.completed = function () { this.done = true; this.activeCount === 0 && this.o.onCompleted(); };

        function InnerObserver(parent, sad) {
            this.parent = parent;
            this.sad = sad;
            __super__.call(this);
        }

        inherits(InnerObserver, __super__);

        InnerObserver.prototype.next = function (x) { this.parent.o.onNext(x); };
        InnerObserver.prototype.error = function (e) { this.parent.o.onError(e); };
        InnerObserver.prototype.completed = function () {
            this.parent.g.remove(this.sad);
            if (this.parent.q.length > 0) {
                this.parent.handleSubscribe(this.parent.q.shift());
            } else {
                this.parent.activeCount--;
                this.parent.done && this.parent.activeCount === 0 && this.parent.o.onCompleted();
            }
        };

        return MergeObserver;
    }(AbstractObserver));

    /**
    * Merges an observable sequence of observable sequences into an observable sequence, limiting the number of concurrent subscriptions to inner sequences.
    * Or merges two observable sequences into a single observable sequence.
    * @param {Mixed} [maxConcurrentOrOther] Maximum number of inner observable sequences being subscribed to concurrently or the second observable sequence.
    * @returns {Observable} The observable sequence that merges the elements of the inner sequences.
    */
    observableProto.merge = function (maxConcurrentOrOther) {
        return typeof maxConcurrentOrOther !== 'number' ?
          observableMerge(this, maxConcurrentOrOther) :
          new MergeObservable(this, maxConcurrentOrOther);
    };

    /**
     * Merges all the observable sequences into a single observable sequence.
     * The scheduler is optional and if not specified, the immediate scheduler is used.
     * @returns {Observable} The observable sequence that merges the elements of the observable sequences.
     */
    var observableMerge = Observable.merge = function () {
        var scheduler, sources = [], i, len = arguments.length;
        if (!arguments[0]) {
            scheduler = immediateScheduler;
            for (i = 1; i < len; i++) { sources.push(arguments[i]); }
        } else if (isScheduler(arguments[0])) {
            scheduler = arguments[0];
            for (i = 1; i < len; i++) { sources.push(arguments[i]); }
        } else {
            scheduler = immediateScheduler;
            for (i = 0; i < len; i++) { sources.push(arguments[i]); }
        }
        if (Array.isArray(sources[0])) {
            sources = sources[0];
        }
        return observableOf(scheduler, sources).mergeAll();
    };

    var CompositeError = Rx.CompositeError = function (errors) {
        this.innerErrors = errors;
        this.message = 'This contains multiple errors. Check the innerErrors';
        Error.call(this);
    };
    CompositeError.prototype = Object.create(Error.prototype);
    CompositeError.prototype.name = 'CompositeError';

    var MergeDelayErrorObservable = (function (__super__) {
        inherits(MergeDelayErrorObservable, __super__);
        function MergeDelayErrorObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        MergeDelayErrorObservable.prototype.subscribeCore = function (o) {
            var group = new CompositeDisposable(),
              m = new SingleAssignmentDisposable(),
              state = { isStopped: false, errors: [], o: o };

            group.add(m);
            m.setDisposable(this.source.subscribe(new MergeDelayErrorObserver(group, state)));

            return group;
        };

        return MergeDelayErrorObservable;
    }(ObservableBase));

    var MergeDelayErrorObserver = (function (__super__) {
        inherits(MergeDelayErrorObserver, __super__);
        function MergeDelayErrorObserver(group, state) {
            this._group = group;
            this._state = state;
            __super__.call(this);
        }

        function setCompletion(o, errors) {
            if (errors.length === 0) {
                o.onCompleted();
            } else if (errors.length === 1) {
                o.onError(errors[0]);
            } else {
                o.onError(new CompositeError(errors));
            }
        }

        MergeDelayErrorObserver.prototype.next = function (x) {
            var inner = new SingleAssignmentDisposable();
            this._group.add(inner);

            // Check for promises support
            isPromise(x) && (x = observableFromPromise(x));
            inner.setDisposable(x.subscribe(new InnerObserver(inner, this._group, this._state)));
        };

        MergeDelayErrorObserver.prototype.error = function (e) {
            this._state.errors.push(e);
            this._state.isStopped = true;
            this._group.length === 1 && setCompletion(this._state.o, this._state.errors);
        };

        MergeDelayErrorObserver.prototype.completed = function () {
            this._state.isStopped = true;
            this._group.length === 1 && setCompletion(this._state.o, this._state.errors);
        };

        inherits(InnerObserver, __super__);
        function InnerObserver(inner, group, state) {
            this._inner = inner;
            this._group = group;
            this._state = state;
            __super__.call(this);
        }

        InnerObserver.prototype.next = function (x) { this._state.o.onNext(x); };
        InnerObserver.prototype.error = function (e) {
            this._state.errors.push(e);
            this._group.remove(this._inner);
            this._state.isStopped && this._group.length === 1 && setCompletion(this._state.o, this._state.errors);
        };
        InnerObserver.prototype.completed = function () {
            this._group.remove(this._inner);
            this._state.isStopped && this._group.length === 1 && setCompletion(this._state.o, this._state.errors);
        };

        return MergeDelayErrorObserver;
    }(AbstractObserver));

    /**
    * Flattens an Observable that emits Observables into one Observable, in a way that allows an Observer to
    * receive all successfully emitted items from all of the source Observables without being interrupted by
    * an error notification from one of them.
    *
    * This behaves like Observable.prototype.mergeAll except that if any of the merged Observables notify of an
    * error via the Observer's onError, mergeDelayError will refrain from propagating that
    * error notification until all of the merged Observables have finished emitting items.
    * @param {Array | Arguments} args Arguments or an array to merge.
    * @returns {Observable} an Observable that emits all of the items emitted by the Observables emitted by the Observable
    */
    Observable.mergeDelayError = function () {
        var args;
        if (Array.isArray(arguments[0])) {
            args = arguments[0];
        } else {
            var len = arguments.length;
            args = new Array(len);
            for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        }
        var source = observableOf(null, args);
        return new MergeDelayErrorObservable(source);
    };

    var MergeAllObservable = (function (__super__) {
        inherits(MergeAllObservable, __super__);

        function MergeAllObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        MergeAllObservable.prototype.subscribeCore = function (o) {
            var g = new CompositeDisposable(), m = new SingleAssignmentDisposable();
            g.add(m);
            m.setDisposable(this.source.subscribe(new MergeAllObserver(o, g)));
            return g;
        };

        return MergeAllObservable;
    }(ObservableBase));

    var MergeAllObserver = (function (__super__) {
        function MergeAllObserver(o, g) {
            this.o = o;
            this.g = g;
            this.done = false;
            __super__.call(this);
        }

        inherits(MergeAllObserver, __super__);

        MergeAllObserver.prototype.next = function (innerSource) {
            var sad = new SingleAssignmentDisposable();
            this.g.add(sad);
            isPromise(innerSource) && (innerSource = observableFromPromise(innerSource));
            sad.setDisposable(innerSource.subscribe(new InnerObserver(this, sad)));
        };

        MergeAllObserver.prototype.error = function (e) {
            this.o.onError(e);
        };

        MergeAllObserver.prototype.completed = function () {
            this.done = true;
            this.g.length === 1 && this.o.onCompleted();
        };

        function InnerObserver(parent, sad) {
            this.parent = parent;
            this.sad = sad;
            __super__.call(this);
        }

        inherits(InnerObserver, __super__);

        InnerObserver.prototype.next = function (x) {
            this.parent.o.onNext(x);
        };
        InnerObserver.prototype.error = function (e) {
            this.parent.o.onError(e);
        };
        InnerObserver.prototype.completed = function () {
            this.parent.g.remove(this.sad);
            this.parent.done && this.parent.g.length === 1 && this.parent.o.onCompleted();
        };

        return MergeAllObserver;
    }(AbstractObserver));

    /**
    * Merges an observable sequence of observable sequences into an observable sequence.
    * @returns {Observable} The observable sequence that merges the elements of the inner sequences.
    */
    observableProto.mergeAll = function () {
        return new MergeAllObservable(this);
    };

    var SkipUntilObservable = (function (__super__) {
        inherits(SkipUntilObservable, __super__);

        function SkipUntilObservable(source, other) {
            this._s = source;
            this._o = isPromise(other) ? observableFromPromise(other) : other;
            this._open = false;
            __super__.call(this);
        }

        SkipUntilObservable.prototype.subscribeCore = function (o) {
            var leftSubscription = new SingleAssignmentDisposable();
            leftSubscription.setDisposable(this._s.subscribe(new SkipUntilSourceObserver(o, this)));

            isPromise(this._o) && (this._o = observableFromPromise(this._o));

            var rightSubscription = new SingleAssignmentDisposable();
            rightSubscription.setDisposable(this._o.subscribe(new SkipUntilOtherObserver(o, this, rightSubscription)));

            return new BinaryDisposable(leftSubscription, rightSubscription);
        };

        return SkipUntilObservable;
    }(ObservableBase));

    var SkipUntilSourceObserver = (function (__super__) {
        inherits(SkipUntilSourceObserver, __super__);
        function SkipUntilSourceObserver(o, p) {
            this._o = o;
            this._p = p;
            __super__.call(this);
        }

        SkipUntilSourceObserver.prototype.next = function (x) {
            this._p._open && this._o.onNext(x);
        };

        SkipUntilSourceObserver.prototype.error = function (err) {
            this._o.onError(err);
        };

        SkipUntilSourceObserver.prototype.onCompleted = function () {
            this._p._open && this._o.onCompleted();
        };

        return SkipUntilSourceObserver;
    }(AbstractObserver));

    var SkipUntilOtherObserver = (function (__super__) {
        inherits(SkipUntilOtherObserver, __super__);
        function SkipUntilOtherObserver(o, p, r) {
            this._o = o;
            this._p = p;
            this._r = r;
            __super__.call(this);
        }

        SkipUntilOtherObserver.prototype.next = function () {
            this._p._open = true;
            this._r.dispose();
        };

        SkipUntilOtherObserver.prototype.error = function (err) {
            this._o.onError(err);
        };

        SkipUntilOtherObserver.prototype.onCompleted = function () {
            this._r.dispose();
        };

        return SkipUntilOtherObserver;
    }(AbstractObserver));

    /**
     * Returns the values from the source observable sequence only after the other observable sequence produces a value.
     * @param {Observable | Promise} other The observable sequence or Promise that triggers propagation of elements of the source sequence.
     * @returns {Observable} An observable sequence containing the elements of the source sequence starting from the point the other sequence triggered propagation.
     */
    observableProto.skipUntil = function (other) {
        return new SkipUntilObservable(this, other);
    };

    var SwitchObservable = (function (__super__) {
        inherits(SwitchObservable, __super__);
        function SwitchObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        SwitchObservable.prototype.subscribeCore = function (o) {
            var inner = new SerialDisposable(), s = this.source.subscribe(new SwitchObserver(o, inner));
            return new BinaryDisposable(s, inner);
        };

        inherits(SwitchObserver, AbstractObserver);
        function SwitchObserver(o, inner) {
            this.o = o;
            this.inner = inner;
            this.stopped = false;
            this.latest = 0;
            this.hasLatest = false;
            AbstractObserver.call(this);
        }

        SwitchObserver.prototype.next = function (innerSource) {
            var d = new SingleAssignmentDisposable(), id = ++this.latest;
            this.hasLatest = true;
            this.inner.setDisposable(d);
            isPromise(innerSource) && (innerSource = observableFromPromise(innerSource));
            d.setDisposable(innerSource.subscribe(new InnerObserver(this, id)));
        };

        SwitchObserver.prototype.error = function (e) {
            this.o.onError(e);
        };

        SwitchObserver.prototype.completed = function () {
            this.stopped = true;
            !this.hasLatest && this.o.onCompleted();
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(parent, id) {
            this.parent = parent;
            this.id = id;
            AbstractObserver.call(this);
        }
        InnerObserver.prototype.next = function (x) {
            this.parent.latest === this.id && this.parent.o.onNext(x);
        };

        InnerObserver.prototype.error = function (e) {
            this.parent.latest === this.id && this.parent.o.onError(e);
        };

        InnerObserver.prototype.completed = function () {
            if (this.parent.latest === this.id) {
                this.parent.hasLatest = false;
                this.parent.stopped && this.parent.o.onCompleted();
            }
        };

        return SwitchObservable;
    }(ObservableBase));

    /**
    * Transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence.
    * @returns {Observable} The observable sequence that at any point in time produces the elements of the most recent inner observable sequence that has been received.
    */
    observableProto['switch'] = observableProto.switchLatest = function () {
        return new SwitchObservable(this);
    };

    var TakeUntilObservable = (function (__super__) {
        inherits(TakeUntilObservable, __super__);

        function TakeUntilObservable(source, other) {
            this.source = source;
            this.other = isPromise(other) ? observableFromPromise(other) : other;
            __super__.call(this);
        }

        TakeUntilObservable.prototype.subscribeCore = function (o) {
            return new BinaryDisposable(
              this.source.subscribe(o),
              this.other.subscribe(new TakeUntilObserver(o))
            );
        };

        return TakeUntilObservable;
    }(ObservableBase));

    var TakeUntilObserver = (function (__super__) {
        inherits(TakeUntilObserver, __super__);
        function TakeUntilObserver(o) {
            this._o = o;
            __super__.call(this);
        }

        TakeUntilObserver.prototype.next = function () {
            this._o.onCompleted();
        };

        TakeUntilObserver.prototype.error = function (err) {
            this._o.onError(err);
        };

        TakeUntilObserver.prototype.onCompleted = noop;

        return TakeUntilObserver;
    }(AbstractObserver));

    /**
     * Returns the values from the source observable sequence until the other observable sequence produces a value.
     * @param {Observable | Promise} other Observable sequence or Promise that terminates propagation of elements of the source sequence.
     * @returns {Observable} An observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation.
     */
    observableProto.takeUntil = function (other) {
        return new TakeUntilObservable(this, other);
    };

    function falseFactory() { return false; }
    function argumentsToArray() {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        return args;
    }

    var WithLatestFromObservable = (function (__super__) {
        inherits(WithLatestFromObservable, __super__);
        function WithLatestFromObservable(source, sources, resultSelector) {
            this._s = source;
            this._ss = sources;
            this._cb = resultSelector;
            __super__.call(this);
        }

        WithLatestFromObservable.prototype.subscribeCore = function (o) {
            var len = this._ss.length;
            var state = {
                hasValue: arrayInitialize(len, falseFactory),
                hasValueAll: false,
                values: new Array(len)
            };

            var n = this._ss.length, subscriptions = new Array(n + 1);
            for (var i = 0; i < n; i++) {
                var other = this._ss[i], sad = new SingleAssignmentDisposable();
                isPromise(other) && (other = observableFromPromise(other));
                sad.setDisposable(other.subscribe(new WithLatestFromOtherObserver(o, i, state)));
                subscriptions[i] = sad;
            }

            var outerSad = new SingleAssignmentDisposable();
            outerSad.setDisposable(this._s.subscribe(new WithLatestFromSourceObserver(o, this._cb, state)));
            subscriptions[n] = outerSad;

            return new NAryDisposable(subscriptions);
        };

        return WithLatestFromObservable;
    }(ObservableBase));

    var WithLatestFromOtherObserver = (function (__super__) {
        inherits(WithLatestFromOtherObserver, __super__);
        function WithLatestFromOtherObserver(o, i, state) {
            this._o = o;
            this._i = i;
            this._state = state;
            __super__.call(this);
        }

        WithLatestFromOtherObserver.prototype.next = function (x) {
            this._state.values[this._i] = x;
            this._state.hasValue[this._i] = true;
            this._state.hasValueAll = this._state.hasValue.every(identity);
        };

        WithLatestFromOtherObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        WithLatestFromOtherObserver.prototype.completed = noop;

        return WithLatestFromOtherObserver;
    }(AbstractObserver));

    var WithLatestFromSourceObserver = (function (__super__) {
        inherits(WithLatestFromSourceObserver, __super__);
        function WithLatestFromSourceObserver(o, cb, state) {
            this._o = o;
            this._cb = cb;
            this._state = state;
            __super__.call(this);
        }

        WithLatestFromSourceObserver.prototype.next = function (x) {
            var allValues = [x].concat(this._state.values);
            if (!this._state.hasValueAll) { return; }
            var res = tryCatch(this._cb).apply(null, allValues);
            if (res === errorObj) { return this._o.onError(res.e); }
            this._o.onNext(res);
        };

        WithLatestFromSourceObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        WithLatestFromSourceObserver.prototype.completed = function () {
            this._o.onCompleted();
        };

        return WithLatestFromSourceObserver;
    }(AbstractObserver));

    /**
     * Merges the specified observable sequences into one observable sequence by using the selector function only when the (first) source observable sequence produces an element.
     * @returns {Observable} An observable sequence containing the result of combining elements of the sources using the specified result selector function.
     */
    observableProto.withLatestFrom = function () {
        if (arguments.length === 0) { throw new Error('invalid arguments'); }

        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        var resultSelector = isFunction(args[len - 1]) ? args.pop() : argumentsToArray;
        Array.isArray(args[0]) && (args = args[0]);

        return new WithLatestFromObservable(this, args, resultSelector);
    };

    function falseFactory() { return false; }
    function emptyArrayFactory() { return []; }

    var ZipObservable = (function (__super__) {
        inherits(ZipObservable, __super__);
        function ZipObservable(sources, resultSelector) {
            this._s = sources;
            this._cb = resultSelector;
            __super__.call(this);
        }

        ZipObservable.prototype.subscribeCore = function (observer) {
            var n = this._s.length,
                subscriptions = new Array(n),
                done = arrayInitialize(n, falseFactory),
                q = arrayInitialize(n, emptyArrayFactory);

            for (var i = 0; i < n; i++) {
                var source = this._s[i], sad = new SingleAssignmentDisposable();
                subscriptions[i] = sad;
                isPromise(source) && (source = observableFromPromise(source));
                sad.setDisposable(source.subscribe(new ZipObserver(observer, i, this, q, done)));
            }

            return new NAryDisposable(subscriptions);
        };

        return ZipObservable;
    }(ObservableBase));

    var ZipObserver = (function (__super__) {
        inherits(ZipObserver, __super__);
        function ZipObserver(o, i, p, q, d) {
            this._o = o;
            this._i = i;
            this._p = p;
            this._q = q;
            this._d = d;
            __super__.call(this);
        }

        function notEmpty(x) { return x.length > 0; }
        function shiftEach(x) { return x.shift(); }
        function notTheSame(i) {
            return function (x, j) {
                return j !== i;
            };
        }

        ZipObserver.prototype.next = function (x) {
            this._q[this._i].push(x);
            if (this._q.every(notEmpty)) {
                var queuedValues = this._q.map(shiftEach);
                var res = tryCatch(this._p._cb).apply(null, queuedValues);
                if (res === errorObj) { return this._o.onError(res.e); }
                this._o.onNext(res);
            } else if (this._d.filter(notTheSame(this._i)).every(identity)) {
                this._o.onCompleted();
            }
        };

        ZipObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        ZipObserver.prototype.completed = function () {
            this._d[this._i] = true;
            this._d.every(identity) && this._o.onCompleted();
        };

        return ZipObserver;
    }(AbstractObserver));

    /**
     * Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences or an array have produced an element at a corresponding index.
     * The last element in the arguments must be a function to invoke for each series of elements at corresponding indexes in the args.
     * @returns {Observable} An observable sequence containing the result of combining elements of the args using the specified result selector function.
     */
    observableProto.zip = function () {
        if (arguments.length === 0) { throw new Error('invalid arguments'); }

        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        var resultSelector = isFunction(args[len - 1]) ? args.pop() : argumentsToArray;
        Array.isArray(args[0]) && (args = args[0]);

        var parent = this;
        args.unshift(parent);

        return new ZipObservable(args, resultSelector);
    };

    /**
     * Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences have produced an element at a corresponding index.
     * @param arguments Observable sources.
     * @param {Function} resultSelector Function to invoke for each series of elements at corresponding indexes in the sources.
     * @returns {Observable} An observable sequence containing the result of combining elements of the sources using the specified result selector function.
     */
    Observable.zip = function () {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        if (Array.isArray(args[0])) {
            args = isFunction(args[1]) ? args[0].concat(args[1]) : args[0];
        }
        var first = args.shift();
        return first.zip.apply(first, args);
    };

    function falseFactory() { return false; }
    function emptyArrayFactory() { return []; }
    function argumentsToArray() {
        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        return args;
    }

    var ZipIterableObservable = (function (__super__) {
        inherits(ZipIterableObservable, __super__);
        function ZipIterableObservable(sources, cb) {
            this.sources = sources;
            this._cb = cb;
            __super__.call(this);
        }

        ZipIterableObservable.prototype.subscribeCore = function (o) {
            var sources = this.sources, len = sources.length, subscriptions = new Array(len);

            var state = {
                q: arrayInitialize(len, emptyArrayFactory),
                done: arrayInitialize(len, falseFactory),
                cb: this._cb,
                o: o
            };

            for (var i = 0; i < len; i++) {
                (function (i) {
                    var source = sources[i], sad = new SingleAssignmentDisposable();
                    (isArrayLike(source) || isIterable(source)) && (source = observableFrom(source));

                    subscriptions[i] = sad;
                    sad.setDisposable(source.subscribe(new ZipIterableObserver(state, i)));
                }(i));
            }

            return new NAryDisposable(subscriptions);
        };

        return ZipIterableObservable;
    }(ObservableBase));

    var ZipIterableObserver = (function (__super__) {
        inherits(ZipIterableObserver, __super__);
        function ZipIterableObserver(s, i) {
            this._s = s;
            this._i = i;
            __super__.call(this);
        }

        function notEmpty(x) { return x.length > 0; }
        function shiftEach(x) { return x.shift(); }
        function notTheSame(i) {
            return function (x, j) {
                return j !== i;
            };
        }

        ZipIterableObserver.prototype.next = function (x) {
            this._s.q[this._i].push(x);
            if (this._s.q.every(notEmpty)) {
                var queuedValues = this._s.q.map(shiftEach),
                    res = tryCatch(this._s.cb).apply(null, queuedValues);
                if (res === errorObj) { return this._s.o.onError(res.e); }
                this._s.o.onNext(res);
            } else if (this._s.done.filter(notTheSame(this._i)).every(identity)) {
                this._s.o.onCompleted();
            }
        };

        ZipIterableObserver.prototype.error = function (e) { this._s.o.onError(e); };

        ZipIterableObserver.prototype.completed = function () {
            this._s.done[this._i] = true;
            this._s.done.every(identity) && this._s.o.onCompleted();
        };

        return ZipIterableObserver;
    }(AbstractObserver));

    /**
     * Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences or an array have produced an element at a corresponding index.
     * The last element in the arguments must be a function to invoke for each series of elements at corresponding indexes in the args.
     * @returns {Observable} An observable sequence containing the result of combining elements of the args using the specified result selector function.
     */
    observableProto.zipIterable = function () {
        if (arguments.length === 0) { throw new Error('invalid arguments'); }

        var len = arguments.length, args = new Array(len);
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        var resultSelector = isFunction(args[len - 1]) ? args.pop() : argumentsToArray;

        var parent = this;
        args.unshift(parent);
        return new ZipIterableObservable(args, resultSelector);
    };

    function asObservable(source) {
        return function subscribe(o) { return source.subscribe(o); };
    }

    /**
     *  Hides the identity of an observable sequence.
     * @returns {Observable} An observable sequence that hides the identity of the source sequence.
     */
    observableProto.asObservable = function () {
        return new AnonymousObservable(asObservable(this), this);
    };

    var DematerializeObservable = (function (__super__) {
        inherits(DematerializeObservable, __super__);
        function DematerializeObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        DematerializeObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new DematerializeObserver(o));
        };

        return DematerializeObservable;
    }(ObservableBase));

    var DematerializeObserver = (function (__super__) {
        inherits(DematerializeObserver, __super__);

        function DematerializeObserver(o) {
            this._o = o;
            __super__.call(this);
        }

        DematerializeObserver.prototype.next = function (x) { x.accept(this._o); };
        DematerializeObserver.prototype.error = function (e) { this._o.onError(e); };
        DematerializeObserver.prototype.completed = function () { this._o.onCompleted(); };

        return DematerializeObserver;
    }(AbstractObserver));

    /**
     * Dematerializes the explicit notification values of an observable sequence as implicit notifications.
     * @returns {Observable} An observable sequence exhibiting the behavior corresponding to the source sequence's notification values.
     */
    observableProto.dematerialize = function () {
        return new DematerializeObservable(this);
    };

    var DistinctUntilChangedObservable = (function (__super__) {
        inherits(DistinctUntilChangedObservable, __super__);
        function DistinctUntilChangedObservable(source, keyFn, comparer) {
            this.source = source;
            this.keyFn = keyFn;
            this.comparer = comparer;
            __super__.call(this);
        }

        DistinctUntilChangedObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new DistinctUntilChangedObserver(o, this.keyFn, this.comparer));
        };

        return DistinctUntilChangedObservable;
    }(ObservableBase));

    var DistinctUntilChangedObserver = (function (__super__) {
        inherits(DistinctUntilChangedObserver, __super__);
        function DistinctUntilChangedObserver(o, keyFn, comparer) {
            this.o = o;
            this.keyFn = keyFn;
            this.comparer = comparer;
            this.hasCurrentKey = false;
            this.currentKey = null;
            __super__.call(this);
        }

        DistinctUntilChangedObserver.prototype.next = function (x) {
            var key = x, comparerEquals;
            if (isFunction(this.keyFn)) {
                key = tryCatch(this.keyFn)(x);
                if (key === errorObj) { return this.o.onError(key.e); }
            }
            if (this.hasCurrentKey) {
                comparerEquals = tryCatch(this.comparer)(this.currentKey, key);
                if (comparerEquals === errorObj) { return this.o.onError(comparerEquals.e); }
            }
            if (!this.hasCurrentKey || !comparerEquals) {
                this.hasCurrentKey = true;
                this.currentKey = key;
                this.o.onNext(x);
            }
        };
        DistinctUntilChangedObserver.prototype.error = function (e) {
            this.o.onError(e);
        };
        DistinctUntilChangedObserver.prototype.completed = function () {
            this.o.onCompleted();
        };

        return DistinctUntilChangedObserver;
    }(AbstractObserver));

    /**
    *  Returns an observable sequence that contains only distinct contiguous elements according to the keyFn and the comparer.
    * @param {Function} [keyFn] A function to compute the comparison key for each element. If not provided, it projects the value.
    * @param {Function} [comparer] Equality comparer for computed key values. If not provided, defaults to an equality comparer function.
    * @returns {Observable} An observable sequence only containing the distinct contiguous elements, based on a computed key value, from the source sequence.
    */
    observableProto.distinctUntilChanged = function (keyFn, comparer) {
        comparer || (comparer = defaultComparer);
        return new DistinctUntilChangedObservable(this, keyFn, comparer);
    };

    var TapObservable = (function (__super__) {
        inherits(TapObservable, __super__);
        function TapObservable(source, observerOrOnNext, onError, onCompleted) {
            this.source = source;
            this._oN = observerOrOnNext;
            this._oE = onError;
            this._oC = onCompleted;
            __super__.call(this);
        }

        TapObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o, this));
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(o, p) {
            this.o = o;
            this.t = !p._oN || isFunction(p._oN) ?
              observerCreate(p._oN || noop, p._oE || noop, p._oC || noop) :
              p._oN;
            this.isStopped = false;
            AbstractObserver.call(this);
        }
        InnerObserver.prototype.next = function (x) {
            var res = tryCatch(this.t.onNext).call(this.t, x);
            if (res === errorObj) { this.o.onError(res.e); }
            this.o.onNext(x);
        };
        InnerObserver.prototype.error = function (err) {
            var res = tryCatch(this.t.onError).call(this.t, err);
            if (res === errorObj) { return this.o.onError(res.e); }
            this.o.onError(err);
        };
        InnerObserver.prototype.completed = function () {
            var res = tryCatch(this.t.onCompleted).call(this.t);
            if (res === errorObj) { return this.o.onError(res.e); }
            this.o.onCompleted();
        };

        return TapObservable;
    }(ObservableBase));

    /**
    *  Invokes an action for each element in the observable sequence and invokes an action upon graceful or exceptional termination of the observable sequence.
    *  This method can be used for debugging, logging, etc. of query behavior by intercepting the message stream to run arbitrary actions for messages on the pipeline.
    * @param {Function | Observer} observerOrOnNext Action to invoke for each element in the observable sequence or an o.
    * @param {Function} [onError]  Action to invoke upon exceptional termination of the observable sequence. Used if only the observerOrOnNext parameter is also a function.
    * @param {Function} [onCompleted]  Action to invoke upon graceful termination of the observable sequence. Used if only the observerOrOnNext parameter is also a function.
    * @returns {Observable} The source sequence with the side-effecting behavior applied.
    */
    observableProto['do'] = observableProto.tap = observableProto.doAction = function (observerOrOnNext, onError, onCompleted) {
        return new TapObservable(this, observerOrOnNext, onError, onCompleted);
    };

    /**
    *  Invokes an action for each element in the observable sequence.
    *  This method can be used for debugging, logging, etc. of query behavior by intercepting the message stream to run arbitrary actions for messages on the pipeline.
    * @param {Function} onNext Action to invoke for each element in the observable sequence.
    * @param {Any} [thisArg] Object to use as this when executing callback.
    * @returns {Observable} The source sequence with the side-effecting behavior applied.
    */
    observableProto.doOnNext = observableProto.tapOnNext = function (onNext, thisArg) {
        return this.tap(typeof thisArg !== 'undefined' ? function (x) { onNext.call(thisArg, x); } : onNext);
    };

    /**
    *  Invokes an action upon exceptional termination of the observable sequence.
    *  This method can be used for debugging, logging, etc. of query behavior by intercepting the message stream to run arbitrary actions for messages on the pipeline.
    * @param {Function} onError Action to invoke upon exceptional termination of the observable sequence.
    * @param {Any} [thisArg] Object to use as this when executing callback.
    * @returns {Observable} The source sequence with the side-effecting behavior applied.
    */
    observableProto.doOnError = observableProto.tapOnError = function (onError, thisArg) {
        return this.tap(noop, typeof thisArg !== 'undefined' ? function (e) { onError.call(thisArg, e); } : onError);
    };

    /**
    *  Invokes an action upon graceful termination of the observable sequence.
    *  This method can be used for debugging, logging, etc. of query behavior by intercepting the message stream to run arbitrary actions for messages on the pipeline.
    * @param {Function} onCompleted Action to invoke upon graceful termination of the observable sequence.
    * @param {Any} [thisArg] Object to use as this when executing callback.
    * @returns {Observable} The source sequence with the side-effecting behavior applied.
    */
    observableProto.doOnCompleted = observableProto.tapOnCompleted = function (onCompleted, thisArg) {
        return this.tap(noop, null, typeof thisArg !== 'undefined' ? function () { onCompleted.call(thisArg); } : onCompleted);
    };

    var FinallyObservable = (function (__super__) {
        inherits(FinallyObservable, __super__);
        function FinallyObservable(source, fn, thisArg) {
            this.source = source;
            this._fn = bindCallback(fn, thisArg, 0);
            __super__.call(this);
        }

        FinallyObservable.prototype.subscribeCore = function (o) {
            var d = tryCatch(this.source.subscribe).call(this.source, o);
            if (d === errorObj) {
                this._fn();
                thrower(d.e);
            }

            return new FinallyDisposable(d, this._fn);
        };

        function FinallyDisposable(s, fn) {
            this.isDisposed = false;
            this._s = s;
            this._fn = fn;
        }
        FinallyDisposable.prototype.dispose = function () {
            if (!this.isDisposed) {
                var res = tryCatch(this._s.dispose).call(this._s);
                this._fn();
                res === errorObj && thrower(res.e);
            }
        };

        return FinallyObservable;

    }(ObservableBase));

    /**
     *  Invokes a specified action after the source observable sequence terminates gracefully or exceptionally.
     * @param {Function} finallyAction Action to invoke after the source observable sequence terminates.
     * @returns {Observable} Source sequence with the action-invoking termination behavior applied.
     */
    observableProto['finally'] = function (action, thisArg) {
        return new FinallyObservable(this, action, thisArg);
    };

    var IgnoreElementsObservable = (function (__super__) {
        inherits(IgnoreElementsObservable, __super__);

        function IgnoreElementsObservable(source) {
            this.source = source;
            __super__.call(this);
        }

        IgnoreElementsObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o));
        };

        function InnerObserver(o) {
            this.o = o;
            this.isStopped = false;
        }
        InnerObserver.prototype.onNext = noop;
        InnerObserver.prototype.onError = function (err) {
            if (!this.isStopped) {
                this.isStopped = true;
                this.o.onError(err);
            }
        };
        InnerObserver.prototype.onCompleted = function () {
            if (!this.isStopped) {
                this.isStopped = true;
                this.o.onCompleted();
            }
        };
        InnerObserver.prototype.dispose = function () { this.isStopped = true; };
        InnerObserver.prototype.fail = function (e) {
            if (!this.isStopped) {
                this.isStopped = true;
                this.observer.onError(e);
                return true;
            }

            return false;
        };

        return IgnoreElementsObservable;
    }(ObservableBase));

    /**
     *  Ignores all elements in an observable sequence leaving only the termination messages.
     * @returns {Observable} An empty observable sequence that signals termination, successful or exceptional, of the source sequence.
     */
    observableProto.ignoreElements = function () {
        return new IgnoreElementsObservable(this);
    };

    var MaterializeObservable = (function (__super__) {
        inherits(MaterializeObservable, __super__);
        function MaterializeObservable(source, fn) {
            this.source = source;
            __super__.call(this);
        }

        MaterializeObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new MaterializeObserver(o));
        };

        return MaterializeObservable;
    }(ObservableBase));

    var MaterializeObserver = (function (__super__) {
        inherits(MaterializeObserver, __super__);

        function MaterializeObserver(o) {
            this._o = o;
            __super__.call(this);
        }

        MaterializeObserver.prototype.next = function (x) { this._o.onNext(notificationCreateOnNext(x)) };
        MaterializeObserver.prototype.error = function (e) { this._o.onNext(notificationCreateOnError(e)); this._o.onCompleted(); };
        MaterializeObserver.prototype.completed = function () { this._o.onNext(notificationCreateOnCompleted()); this._o.onCompleted(); };

        return MaterializeObserver;
    }(AbstractObserver));

    /**
     *  Materializes the implicit notifications of an observable sequence as explicit notification values.
     * @returns {Observable} An observable sequence containing the materialized notification values from the source sequence.
     */
    observableProto.materialize = function () {
        return new MaterializeObservable(this);
    };

    /**
     *  Repeats the observable sequence a specified number of times. If the repeat count is not specified, the sequence repeats indefinitely.
     * @param {Number} [repeatCount]  Number of times to repeat the sequence. If not provided, repeats the sequence indefinitely.
     * @returns {Observable} The observable sequence producing the elements of the given sequence repeatedly.
     */
    observableProto.repeat = function (repeatCount) {
        return enumerableRepeat(this, repeatCount).concat();
    };

    /**
     *  Repeats the source observable sequence the specified number of times or until it successfully terminates. If the retry count is not specified, it retries indefinitely.
     *  Note if you encounter an error and want it to retry once, then you must use .retry(2);
     *
     * @example
     *  var res = retried = retry.repeat();
     *  var res = retried = retry.repeat(2);
     * @param {Number} [retryCount]  Number of times to retry the sequence. If not provided, retry the sequence indefinitely.
     * @returns {Observable} An observable sequence producing the elements of the given sequence repeatedly until it terminates successfully.
     */
    observableProto.retry = function (retryCount) {
        return enumerableRepeat(this, retryCount).catchError();
    };

    function repeat(value) {
        return {
            '@@iterator': function () {
                return {
                    next: function () {
                        return { done: false, value: value };
                    }
                };
            }
        };
    }

    var RetryWhenObservable = (function (__super__) {
        function createDisposable(state) {
            return {
                isDisposed: false,
                dispose: function () {
                    if (!this.isDisposed) {
                        this.isDisposed = true;
                        state.isDisposed = true;
                    }
                }
            };
        }

        function RetryWhenObservable(source, notifier) {
            this.source = source;
            this._notifier = notifier;
            __super__.call(this);
        }

        inherits(RetryWhenObservable, __super__);

        RetryWhenObservable.prototype.subscribeCore = function (o) {
            var exceptions = new Subject(),
              notifier = new Subject(),
              handled = this._notifier(exceptions),
              notificationDisposable = handled.subscribe(notifier);

            var e = this.source['@@iterator']();

            var state = { isDisposed: false },
              lastError,
              subscription = new SerialDisposable();
            var cancelable = currentThreadScheduler.scheduleRecursive(null, function (_, recurse) {
                if (state.isDisposed) { return; }
                var currentItem = e.next();

                if (currentItem.done) {
                    if (lastError) {
                        o.onError(lastError);
                    } else {
                        o.onCompleted();
                    }
                    return;
                }

                // Check if promise
                var currentValue = currentItem.value;
                isPromise(currentValue) && (currentValue = observableFromPromise(currentValue));

                var outer = new SingleAssignmentDisposable();
                var inner = new SingleAssignmentDisposable();
                subscription.setDisposable(new BinaryDisposable(inner, outer));
                outer.setDisposable(currentValue.subscribe(
                  function (x) { o.onNext(x); },
                  function (exn) {
                      inner.setDisposable(notifier.subscribe(recurse, function (ex) {
                          o.onError(ex);
                      }, function () {
                          o.onCompleted();
                      }));

                      exceptions.onNext(exn);
                      outer.dispose();
                  },
                  function () { o.onCompleted(); }));
            });

            return new NAryDisposable([notificationDisposable, subscription, cancelable, createDisposable(state)]);
        };

        return RetryWhenObservable;
    }(ObservableBase));

    observableProto.retryWhen = function (notifier) {
        return new RetryWhenObservable(repeat(this), notifier);
    };

    function repeat(value) {
        return {
            '@@iterator': function () {
                return {
                    next: function () {
                        return { done: false, value: value };
                    }
                };
            }
        };
    }

    var RepeatWhenObservable = (function (__super__) {
        function createDisposable(state) {
            return {
                isDisposed: false,
                dispose: function () {
                    if (!this.isDisposed) {
                        this.isDisposed = true;
                        state.isDisposed = true;
                    }
                }
            };
        }

        function RepeatWhenObservable(source, notifier) {
            this.source = source;
            this._notifier = notifier;
            __super__.call(this);
        }

        inherits(RepeatWhenObservable, __super__);

        RepeatWhenObservable.prototype.subscribeCore = function (o) {
            var completions = new Subject(),
              notifier = new Subject(),
              handled = this._notifier(completions),
              notificationDisposable = handled.subscribe(notifier);

            var e = this.source['@@iterator']();

            var state = { isDisposed: false },
              lastError,
              subscription = new SerialDisposable();
            var cancelable = currentThreadScheduler.scheduleRecursive(null, function (_, recurse) {
                if (state.isDisposed) { return; }
                var currentItem = e.next();

                if (currentItem.done) {
                    if (lastError) {
                        o.onError(lastError);
                    } else {
                        o.onCompleted();
                    }
                    return;
                }

                // Check if promise
                var currentValue = currentItem.value;
                isPromise(currentValue) && (currentValue = observableFromPromise(currentValue));

                var outer = new SingleAssignmentDisposable();
                var inner = new SingleAssignmentDisposable();
                subscription.setDisposable(new BinaryDisposable(inner, outer));
                outer.setDisposable(currentValue.subscribe(
                  function (x) { o.onNext(x); },
                  function (exn) { o.onError(exn); },
                  function () {
                      inner.setDisposable(notifier.subscribe(recurse, function (ex) {
                          o.onError(ex);
                      }, function () {
                          o.onCompleted();
                      }));

                      completions.onNext(null);
                      outer.dispose();
                  }));
            });

            return new NAryDisposable([notificationDisposable, subscription, cancelable, createDisposable(state)]);
        };

        return RepeatWhenObservable;
    }(ObservableBase));

    observableProto.repeatWhen = function (notifier) {
        return new RepeatWhenObservable(repeat(this), notifier);
    };

    var ScanObservable = (function (__super__) {
        inherits(ScanObservable, __super__);
        function ScanObservable(source, accumulator, hasSeed, seed) {
            this.source = source;
            this.accumulator = accumulator;
            this.hasSeed = hasSeed;
            this.seed = seed;
            __super__.call(this);
        }

        ScanObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new ScanObserver(o, this));
        };

        return ScanObservable;
    }(ObservableBase));

    var ScanObserver = (function (__super__) {
        inherits(ScanObserver, __super__);
        function ScanObserver(o, parent) {
            this._o = o;
            this._p = parent;
            this._fn = parent.accumulator;
            this._hs = parent.hasSeed;
            this._s = parent.seed;
            this._ha = false;
            this._a = null;
            this._hv = false;
            this._i = 0;
            __super__.call(this);
        }

        ScanObserver.prototype.next = function (x) {
            !this._hv && (this._hv = true);
            if (this._ha) {
                this._a = tryCatch(this._fn)(this._a, x, this._i, this._p);
            } else {
                this._a = this._hs ? tryCatch(this._fn)(this._s, x, this._i, this._p) : x;
                this._ha = true;
            }
            if (this._a === errorObj) { return this._o.onError(this._a.e); }
            this._o.onNext(this._a);
            this._i++;
        };

        ScanObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        ScanObserver.prototype.completed = function () {
            !this._hv && this._hs && this._o.onNext(this._s);
            this._o.onCompleted();
        };

        return ScanObserver;
    }(AbstractObserver));

    /**
    *  Applies an accumulator function over an observable sequence and returns each intermediate result. The optional seed value is used as the initial accumulator value.
    *  For aggregation behavior with no intermediate results, see Observable.aggregate.
    * @param {Mixed} [seed] The initial accumulator value.
    * @param {Function} accumulator An accumulator function to be invoked on each element.
    * @returns {Observable} An observable sequence containing the accumulated values.
    */
    observableProto.scan = function () {
        var hasSeed = false, seed, accumulator = arguments[0];
        if (arguments.length === 2) {
            hasSeed = true;
            seed = arguments[1];
        }
        return new ScanObservable(this, accumulator, hasSeed, seed);
    };

    var SkipLastObservable = (function (__super__) {
        inherits(SkipLastObservable, __super__);
        function SkipLastObservable(source, c) {
            this.source = source;
            this._c = c;
            __super__.call(this);
        }

        SkipLastObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new SkipLastObserver(o, this._c));
        };

        return SkipLastObservable;
    }(ObservableBase));

    var SkipLastObserver = (function (__super__) {
        inherits(SkipLastObserver, __super__);
        function SkipLastObserver(o, c) {
            this._o = o;
            this._c = c;
            this._q = [];
            __super__.call(this);
        }

        SkipLastObserver.prototype.next = function (x) {
            this._q.push(x);
            this._q.length > this._c && this._o.onNext(this._q.shift());
        };

        SkipLastObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        SkipLastObserver.prototype.completed = function () {
            this._o.onCompleted();
        };

        return SkipLastObserver;
    }(AbstractObserver));

    /**
     *  Bypasses a specified number of elements at the end of an observable sequence.
     * @description
     *  This operator accumulates a queue with a length enough to store the first `count` elements. As more elements are
     *  received, elements are taken from the front of the queue and produced on the result sequence. This causes elements to be delayed.
     * @param count Number of elements to bypass at the end of the source sequence.
     * @returns {Observable} An observable sequence containing the source sequence elements except for the bypassed ones at the end.
     */
    observableProto.skipLast = function (count) {
        if (count < 0) { throw new ArgumentOutOfRangeError(); }
        return new SkipLastObservable(this, count);
    };

    /**
     *  Prepends a sequence of values to an observable sequence with an optional scheduler and an argument list of values to prepend.
     *  @example
     *  var res = source.startWith(1, 2, 3);
     *  var res = source.startWith(Rx.Scheduler.timeout, 1, 2, 3);
     * @param {Arguments} args The specified values to prepend to the observable sequence
     * @returns {Observable} The source sequence prepended with the specified values.
     */
    observableProto.startWith = function () {
        var values, scheduler, start = 0;
        if (!!arguments.length && isScheduler(arguments[0])) {
            scheduler = arguments[0];
            start = 1;
        } else {
            scheduler = immediateScheduler;
        }
        for (var args = [], i = start, len = arguments.length; i < len; i++) { args.push(arguments[i]); }
        return observableConcat.apply(null, [observableFromArray(args, scheduler), this]);
    };

    var TakeLastObserver = (function (__super__) {
        inherits(TakeLastObserver, __super__);
        function TakeLastObserver(o, c) {
            this._o = o;
            this._c = c;
            this._q = [];
            __super__.call(this);
        }

        TakeLastObserver.prototype.next = function (x) {
            this._q.push(x);
            this._q.length > this._c && this._q.shift();
        };

        TakeLastObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        TakeLastObserver.prototype.completed = function () {
            while (this._q.length > 0) { this._o.onNext(this._q.shift()); }
            this._o.onCompleted();
        };

        return TakeLastObserver;
    }(AbstractObserver));

    /**
     *  Returns a specified number of contiguous elements from the end of an observable sequence.
     * @description
     *  This operator accumulates a buffer with a length enough to store elements count elements. Upon completion of
     *  the source sequence, this buffer is drained on the result sequence. This causes the elements to be delayed.
     * @param {Number} count Number of elements to take from the end of the source sequence.
     * @returns {Observable} An observable sequence containing the specified number of elements from the end of the source sequence.
     */
    observableProto.takeLast = function (count) {
        if (count < 0) { throw new ArgumentOutOfRangeError(); }
        var source = this;
        return new AnonymousObservable(function (o) {
            return source.subscribe(new TakeLastObserver(o, count));
        }, source);
    };

    observableProto.flatMapConcat = observableProto.concatMap = function (selector, resultSelector, thisArg) {
        return new FlatMapObservable(this, selector, resultSelector, thisArg).merge(1);
    };
    var MapObservable = (function (__super__) {
        inherits(MapObservable, __super__);

        function MapObservable(source, selector, thisArg) {
            this.source = source;
            this.selector = bindCallback(selector, thisArg, 3);
            __super__.call(this);
        }

        function innerMap(selector, self) {
            return function (x, i, o) { return selector.call(this, self.selector(x, i, o), i, o); };
        }

        MapObservable.prototype.internalMap = function (selector, thisArg) {
            return new MapObservable(this.source, innerMap(selector, this), thisArg);
        };

        MapObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o, this.selector, this));
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(o, selector, source) {
            this.o = o;
            this.selector = selector;
            this.source = source;
            this.i = 0;
            AbstractObserver.call(this);
        }

        InnerObserver.prototype.next = function (x) {
            var result = tryCatch(this.selector)(x, this.i++, this.source);
            if (result === errorObj) { return this.o.onError(result.e); }
            this.o.onNext(result);
        };

        InnerObserver.prototype.error = function (e) {
            this.o.onError(e);
        };

        InnerObserver.prototype.completed = function () {
            this.o.onCompleted();
        };

        return MapObservable;

    }(ObservableBase));

    /**
    * Projects each element of an observable sequence into a new form by incorporating the element's index.
    * @param {Function} selector A transform function to apply to each source element; the second parameter of the function represents the index of the source element.
    * @param {Any} [thisArg] Object to use as this when executing callback.
    * @returns {Observable} An observable sequence whose elements are the result of invoking the transform function on each element of source.
    */
    observableProto.map = observableProto.select = function (selector, thisArg) {
        var selectorFn = typeof selector === 'function' ? selector : function () { return selector; };
        return this instanceof MapObservable ?
          this.internalMap(selectorFn, thisArg) :
          new MapObservable(this, selectorFn, thisArg);
    };

    function plucker(args, len) {
        return function mapper(x) {
            var currentProp = x;
            for (var i = 0; i < len; i++) {
                var p = currentProp[args[i]];
                if (typeof p !== 'undefined') {
                    currentProp = p;
                } else {
                    return undefined;
                }
            }
            return currentProp;
        };
    }

    /**
     * Retrieves the value of a specified nested property from all elements in
     * the Observable sequence.
     * @param {Arguments} arguments The nested properties to pluck.
     * @returns {Observable} Returns a new Observable sequence of property values.
     */
    observableProto.pluck = function () {
        var len = arguments.length, args = new Array(len);
        if (len === 0) { throw new Error('List of properties cannot be empty.'); }
        for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
        return this.map(plucker(args, len));
    };

    observableProto.flatMap = observableProto.selectMany = observableProto.mergeMap = function (selector, resultSelector, thisArg) {
        return new FlatMapObservable(this, selector, resultSelector, thisArg).mergeAll();
    };

    observableProto.flatMapLatest = observableProto.switchMap = function (selector, resultSelector, thisArg) {
        return new FlatMapObservable(this, selector, resultSelector, thisArg).switchLatest();
    };

    var SkipObservable = (function (__super__) {
        inherits(SkipObservable, __super__);
        function SkipObservable(source, count) {
            this.source = source;
            this._count = count;
            __super__.call(this);
        }

        SkipObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new SkipObserver(o, this._count));
        };

        function SkipObserver(o, c) {
            this._o = o;
            this._r = c;
            AbstractObserver.call(this);
        }

        inherits(SkipObserver, AbstractObserver);

        SkipObserver.prototype.next = function (x) {
            if (this._r <= 0) {
                this._o.onNext(x);
            } else {
                this._r--;
            }
        };
        SkipObserver.prototype.error = function (e) { this._o.onError(e); };
        SkipObserver.prototype.completed = function () { this._o.onCompleted(); };

        return SkipObservable;
    }(ObservableBase));

    /**
     * Bypasses a specified number of elements in an observable sequence and then returns the remaining elements.
     * @param {Number} count The number of elements to skip before returning the remaining elements.
     * @returns {Observable} An observable sequence that contains the elements that occur after the specified index in the input sequence.
     */
    observableProto.skip = function (count) {
        if (count < 0) { throw new ArgumentOutOfRangeError(); }
        return new SkipObservable(this, count);
    };

    var SkipWhileObservable = (function (__super__) {
        inherits(SkipWhileObservable, __super__);
        function SkipWhileObservable(source, fn) {
            this.source = source;
            this._fn = fn;
            __super__.call(this);
        }

        SkipWhileObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new SkipWhileObserver(o, this));
        };

        return SkipWhileObservable;
    }(ObservableBase));

    var SkipWhileObserver = (function (__super__) {
        inherits(SkipWhileObserver, __super__);

        function SkipWhileObserver(o, p) {
            this._o = o;
            this._p = p;
            this._i = 0;
            this._r = false;
            __super__.call(this);
        }

        SkipWhileObserver.prototype.next = function (x) {
            if (!this._r) {
                var res = tryCatch(this._p._fn)(x, this._i++, this._p);
                if (res === errorObj) { return this._o.onError(res.e); }
                this._r = !res;
            }
            this._r && this._o.onNext(x);
        };
        SkipWhileObserver.prototype.error = function (e) { this._o.onError(e); };
        SkipWhileObserver.prototype.completed = function () { this._o.onCompleted(); };

        return SkipWhileObserver;
    }(AbstractObserver));

    /**
     *  Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements.
     *  The element's index is used in the logic of the predicate function.
     *
     *  var res = source.skipWhile(function (value) { return value < 10; });
     *  var res = source.skipWhile(function (value, index) { return value < 10 || index < 10; });
     * @param {Function} predicate A function to test each element for a condition; the second parameter of the function represents the index of the source element.
     * @param {Any} [thisArg] Object to use as this when executing callback.
     * @returns {Observable} An observable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.
     */
    observableProto.skipWhile = function (predicate, thisArg) {
        var fn = bindCallback(predicate, thisArg, 3);
        return new SkipWhileObservable(this, fn);
    };

    var TakeObservable = (function (__super__) {
        inherits(TakeObservable, __super__);
        function TakeObservable(source, count) {
            this.source = source;
            this._count = count;
            __super__.call(this);
        }

        TakeObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new TakeObserver(o, this._count));
        };

        function TakeObserver(o, c) {
            this._o = o;
            this._c = c;
            this._r = c;
            AbstractObserver.call(this);
        }

        inherits(TakeObserver, AbstractObserver);

        TakeObserver.prototype.next = function (x) {
            if (this._r-- > 0) {
                this._o.onNext(x);
                this._r <= 0 && this._o.onCompleted();
            }
        };

        TakeObserver.prototype.error = function (e) { this._o.onError(e); };
        TakeObserver.prototype.completed = function () { this._o.onCompleted(); };

        return TakeObservable;
    }(ObservableBase));

    /**
     *  Returns a specified number of contiguous elements from the start of an observable sequence, using the specified scheduler for the edge case of take(0).
     * @param {Number} count The number of elements to return.
     * @param {Scheduler} [scheduler] Scheduler used to produce an OnCompleted message in case <paramref name="count count</paramref> is set to 0.
     * @returns {Observable} An observable sequence that contains the specified number of elements from the start of the input sequence.
     */
    observableProto.take = function (count, scheduler) {
        if (count < 0) { throw new ArgumentOutOfRangeError(); }
        if (count === 0) { return observableEmpty(scheduler); }
        return new TakeObservable(this, count);
    };

    var TakeWhileObservable = (function (__super__) {
        inherits(TakeWhileObservable, __super__);
        function TakeWhileObservable(source, fn) {
            this.source = source;
            this._fn = fn;
            __super__.call(this);
        }

        TakeWhileObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new TakeWhileObserver(o, this));
        };

        return TakeWhileObservable;
    }(ObservableBase));

    var TakeWhileObserver = (function (__super__) {
        inherits(TakeWhileObserver, __super__);

        function TakeWhileObserver(o, p) {
            this._o = o;
            this._p = p;
            this._i = 0;
            this._r = true;
            __super__.call(this);
        }

        TakeWhileObserver.prototype.next = function (x) {
            if (this._r) {
                this._r = tryCatch(this._p._fn)(x, this._i++, this._p);
                if (this._r === errorObj) { return this._o.onError(this._r.e); }
            }
            if (this._r) {
                this._o.onNext(x);
            } else {
                this._o.onCompleted();
            }
        };
        TakeWhileObserver.prototype.error = function (e) { this._o.onError(e); };
        TakeWhileObserver.prototype.completed = function () { this._o.onCompleted(); };

        return TakeWhileObserver;
    }(AbstractObserver));

    /**
     *  Returns elements from an observable sequence as long as a specified condition is true.
     *  The element's index is used in the logic of the predicate function.
     * @param {Function} predicate A function to test each element for a condition; the second parameter of the function represents the index of the source element.
     * @param {Any} [thisArg] Object to use as this when executing callback.
     * @returns {Observable} An observable sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes.
     */
    observableProto.takeWhile = function (predicate, thisArg) {
        var fn = bindCallback(predicate, thisArg, 3);
        return new TakeWhileObservable(this, fn);
    };

    var FilterObservable = (function (__super__) {
        inherits(FilterObservable, __super__);

        function FilterObservable(source, predicate, thisArg) {
            this.source = source;
            this.predicate = bindCallback(predicate, thisArg, 3);
            __super__.call(this);
        }

        FilterObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new InnerObserver(o, this.predicate, this));
        };

        function innerPredicate(predicate, self) {
            return function (x, i, o) { return self.predicate(x, i, o) && predicate.call(this, x, i, o); }
        }

        FilterObservable.prototype.internalFilter = function (predicate, thisArg) {
            return new FilterObservable(this.source, innerPredicate(predicate, this), thisArg);
        };

        inherits(InnerObserver, AbstractObserver);
        function InnerObserver(o, predicate, source) {
            this.o = o;
            this.predicate = predicate;
            this.source = source;
            this.i = 0;
            AbstractObserver.call(this);
        }

        InnerObserver.prototype.next = function (x) {
            var shouldYield = tryCatch(this.predicate)(x, this.i++, this.source);
            if (shouldYield === errorObj) {
                return this.o.onError(shouldYield.e);
            }
            shouldYield && this.o.onNext(x);
        };

        InnerObserver.prototype.error = function (e) {
            this.o.onError(e);
        };

        InnerObserver.prototype.completed = function () {
            this.o.onCompleted();
        };

        return FilterObservable;

    }(ObservableBase));

    /**
    *  Filters the elements of an observable sequence based on a predicate by incorporating the element's index.
    * @param {Function} predicate A function to test each source element for a condition; the second parameter of the function represents the index of the source element.
    * @param {Any} [thisArg] Object to use as this when executing callback.
    * @returns {Observable} An observable sequence that contains elements from the input sequence that satisfy the condition.
    */
    observableProto.filter = observableProto.where = function (predicate, thisArg) {
        return this instanceof FilterObservable ? this.internalFilter(predicate, thisArg) :
          new FilterObservable(this, predicate, thisArg);
    };

    function createCbObservable(fn, ctx, selector, args) {
        var o = new AsyncSubject();

        args.push(createCbHandler(o, ctx, selector));
        fn.apply(ctx, args);

        return o.asObservable();
    }

    function createCbHandler(o, ctx, selector) {
        return function handler() {
            var len = arguments.length, results = new Array(len);
            for (var i = 0; i < len; i++) { results[i] = arguments[i]; }

            if (isFunction(selector)) {
                results = tryCatch(selector).apply(ctx, results);
                if (results === errorObj) { return o.onError(results.e); }
                o.onNext(results);
            } else {
                if (results.length <= 1) {
                    o.onNext(results[0]);
                } else {
                    o.onNext(results);
                }
            }

            o.onCompleted();
        };
    }

    /**
     * Converts a callback function to an observable sequence.
     *
     * @param {Function} fn Function with a callback as the last parameter to convert to an Observable sequence.
     * @param {Mixed} [ctx] The context for the func parameter to be executed.  If not specified, defaults to undefined.
     * @param {Function} [selector] A selector which takes the arguments from the callback to produce a single item to yield on next.
     * @returns {Function} A function, when executed with the required parameters minus the callback, produces an Observable sequence with a single value of the arguments to the callback as an array.
     */
    Observable.fromCallback = function (fn, ctx, selector) {
        return function () {
            typeof ctx === 'undefined' && (ctx = this);

            var len = arguments.length, args = new Array(len)
            for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
            return createCbObservable(fn, ctx, selector, args);
        };
    };

    function createNodeObservable(fn, ctx, selector, args) {
        var o = new AsyncSubject();

        args.push(createNodeHandler(o, ctx, selector));
        fn.apply(ctx, args);

        return o.asObservable();
    }

    function createNodeHandler(o, ctx, selector) {
        return function handler() {
            var err = arguments[0];
            if (err) { return o.onError(err); }

            var len = arguments.length, results = [];
            for (var i = 1; i < len; i++) { results[i - 1] = arguments[i]; }

            if (isFunction(selector)) {
                var results = tryCatch(selector).apply(ctx, results);
                if (results === errorObj) { return o.onError(results.e); }
                o.onNext(results);
            } else {
                if (results.length <= 1) {
                    o.onNext(results[0]);
                } else {
                    o.onNext(results);
                }
            }

            o.onCompleted();
        };
    }

    /**
     * Converts a Node.js callback style function to an observable sequence.  This must be in function (err, ...) format.
     * @param {Function} fn The function to call
     * @param {Mixed} [ctx] The context for the func parameter to be executed.  If not specified, defaults to undefined.
     * @param {Function} [selector] A selector which takes the arguments from the callback minus the error to produce a single item to yield on next.
     * @returns {Function} An async function which when applied, returns an observable sequence with the callback arguments as an array.
     */
    Observable.fromNodeCallback = function (fn, ctx, selector) {
        return function () {
            typeof ctx === 'undefined' && (ctx = this);
            var len = arguments.length, args = new Array(len);
            for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
            return createNodeObservable(fn, ctx, selector, args);
        };
    };

    function isNodeList(el) {
        if (root.StaticNodeList) {
            // IE8 Specific
            // instanceof is slower than Object#toString, but Object#toString will not work as intended in IE8
            return el instanceof root.StaticNodeList || el instanceof root.NodeList;
        } else {
            return Object.prototype.toString.call(el) === '[object NodeList]';
        }
    }

    function ListenDisposable(e, n, fn) {
        this._e = e;
        this._n = n;
        this._fn = fn;
        this._e.addEventListener(this._n, this._fn, false);
        this.isDisposed = false;
    }
    ListenDisposable.prototype.dispose = function () {
        if (!this.isDisposed) {
            this._e.removeEventListener(this._n, this._fn, false);
            this.isDisposed = true;
        }
    };

    function createEventListener(el, eventName, handler) {
        var disposables = new CompositeDisposable();

        // Asume NodeList or HTMLCollection
        var elemToString = Object.prototype.toString.call(el);
        if (isNodeList(el) || elemToString === '[object HTMLCollection]') {
            for (var i = 0, len = el.length; i < len; i++) {
                disposables.add(createEventListener(el.item(i), eventName, handler));
            }
        } else if (el) {
            disposables.add(new ListenDisposable(el, eventName, handler));
        }

        return disposables;
    }

    /**
     * Configuration option to determine whether to use native events only
     */
    Rx.config.useNativeEvents = false;

    var EventObservable = (function (__super__) {
        inherits(EventObservable, __super__);
        function EventObservable(el, name, fn) {
            this._el = el;
            this._n = name;
            this._fn = fn;
            __super__.call(this);
        }

        function createHandler(o, fn) {
            return function handler() {
                var results = arguments[0];
                if (isFunction(fn)) {
                    results = tryCatch(fn).apply(null, arguments);
                    if (results === errorObj) { return o.onError(results.e); }
                }
                o.onNext(results);
            };
        }

        EventObservable.prototype.subscribeCore = function (o) {
            return createEventListener(
              this._el,
              this._n,
              createHandler(o, this._fn));
        };

        return EventObservable;
    }(ObservableBase));

    /**
     * Creates an observable sequence by adding an event listener to the matching DOMElement or each item in the NodeList.
     * @param {Object} element The DOMElement or NodeList to attach a listener.
     * @param {String} eventName The event name to attach the observable sequence.
     * @param {Function} [selector] A selector which takes the arguments from the event handler to produce a single item to yield on next.
     * @returns {Observable} An observable sequence of events from the specified element and the specified event.
     */
    Observable.fromEvent = function (element, eventName, selector) {
        // Node.js specific
        if (element.addListener) {
            return fromEventPattern(
              function (h) { element.addListener(eventName, h); },
              function (h) { element.removeListener(eventName, h); },
              selector);
        }

        // Use only if non-native events are allowed
        if (!Rx.config.useNativeEvents) {
            // Handles jq, Angular.js, Zepto, Marionette, Ember.js
            if (typeof element.on === 'function' && typeof element.off === 'function') {
                return fromEventPattern(
                  function (h) { element.on(eventName, h); },
                  function (h) { element.off(eventName, h); },
                  selector);
            }
        }

        return new EventObservable(element, eventName, selector).publish().refCount();
    };

    var EventPatternObservable = (function (__super__) {
        inherits(EventPatternObservable, __super__);
        function EventPatternObservable(add, del, fn) {
            this._add = add;
            this._del = del;
            this._fn = fn;
            __super__.call(this);
        }

        function createHandler(o, fn) {
            return function handler() {
                var results = arguments[0];
                if (isFunction(fn)) {
                    results = tryCatch(fn).apply(null, arguments);
                    if (results === errorObj) { return o.onError(results.e); }
                }
                o.onNext(results);
            };
        }

        EventPatternObservable.prototype.subscribeCore = function (o) {
            var fn = createHandler(o, this._fn);
            var returnValue = this._add(fn);
            return new EventPatternDisposable(this._del, fn, returnValue);
        };

        function EventPatternDisposable(del, fn, ret) {
            this._del = del;
            this._fn = fn;
            this._ret = ret;
            this.isDisposed = false;
        }

        EventPatternDisposable.prototype.dispose = function () {
            if (!this.isDisposed) {
                isFunction(this._del) && this._del(this._fn, this._ret);
                this.isDisposed = true;
            }
        };

        return EventPatternObservable;
    }(ObservableBase));

    /**
     * Creates an observable sequence from an event emitter via an addHandler/removeHandler pair.
     * @param {Function} addHandler The function to add a handler to the emitter.
     * @param {Function} [removeHandler] The optional function to remove a handler from an emitter.
     * @param {Function} [selector] A selector which takes the arguments from the event handler to produce a single item to yield on next.
     * @returns {Observable} An observable sequence which wraps an event from an event emitter
     */
    var fromEventPattern = Observable.fromEventPattern = function (addHandler, removeHandler, selector) {
        return new EventPatternObservable(addHandler, removeHandler, selector).publish().refCount();
    };

    var FromPromiseObservable = (function (__super__) {
        inherits(FromPromiseObservable, __super__);
        function FromPromiseObservable(p, s) {
            this._p = p;
            this._s = s;
            __super__.call(this);
        }

        function scheduleNext(s, state) {
            var o = state[0], data = state[1];
            o.onNext(data);
            o.onCompleted();
        }

        function scheduleError(s, state) {
            var o = state[0], err = state[1];
            o.onError(err);
        }

        FromPromiseObservable.prototype.subscribeCore = function (o) {
            var sad = new SingleAssignmentDisposable(), self = this, p = this._p;

            if (isFunction(p)) {
                p = tryCatch(p)();
                if (p === errorObj) {
                    o.onError(p.e);
                    return sad;
                }
            }

            p
              .then(function (data) {
                  sad.setDisposable(self._s.schedule([o, data], scheduleNext));
              }, function (err) {
                  sad.setDisposable(self._s.schedule([o, err], scheduleError));
              });

            return sad;
        };

        return FromPromiseObservable;
    }(ObservableBase));

    /**
    * Converts a Promise to an Observable sequence
    * @param {Promise} An ES6 Compliant promise.
    * @returns {Observable} An Observable sequence which wraps the existing promise success and failure.
    */
    var observableFromPromise = Observable.fromPromise = function (promise, scheduler) {
        scheduler || (scheduler = defaultScheduler);
        return new FromPromiseObservable(promise, scheduler);
    };

    /*
     * Converts an existing observable sequence to an ES6 Compatible Promise
     * @example
     * var promise = Rx.Observable.return(42).toPromise(RSVP.Promise);
     *
     * // With config
     * Rx.config.Promise = RSVP.Promise;
     * var promise = Rx.Observable.return(42).toPromise();
     * @param {Function} [promiseCtor] The constructor of the promise. If not provided, it looks for it in Rx.config.Promise.
     * @returns {Promise} An ES6 compatible promise with the last value from the observable sequence.
     */
    observableProto.toPromise = function (promiseCtor) {
        promiseCtor || (promiseCtor = Rx.config.Promise);
        if (!promiseCtor) { throw new NotSupportedError('Promise type not provided nor in Rx.config.Promise'); }
        var source = this;
        return new promiseCtor(function (resolve, reject) {
            // No cancellation can be done
            var value;
            source.subscribe(function (v) {
                value = v;
            }, reject, function () {
                resolve(value);
            });
        });
    };

    /**
     * Invokes the asynchronous function, surfacing the result through an observable sequence.
     * @param {Function} functionAsync Asynchronous function which returns a Promise to run.
     * @returns {Observable} An observable sequence exposing the function's result value, or an exception.
     */
    Observable.startAsync = function (functionAsync) {
        var promise = tryCatch(functionAsync)();
        if (promise === errorObj) { return observableThrow(promise.e); }
        return observableFromPromise(promise);
    };

    var MulticastObservable = (function (__super__) {
        inherits(MulticastObservable, __super__);
        function MulticastObservable(source, fn1, fn2) {
            this.source = source;
            this._fn1 = fn1;
            this._fn2 = fn2;
            __super__.call(this);
        }

        MulticastObservable.prototype.subscribeCore = function (o) {
            var connectable = this.source.multicast(this._fn1());
            return new BinaryDisposable(this._fn2(connectable).subscribe(o), connectable.connect());
        };

        return MulticastObservable;
    }(ObservableBase));

    /**
     * Multicasts the source sequence notifications through an instantiated subject into all uses of the sequence within a selector function. Each
     * subscription to the resulting sequence causes a separate multicast invocation, exposing the sequence resulting from the selector function's
     * invocation. For specializations with fixed subject types, see Publish, PublishLast, and Replay.
     *
     * @example
     * 1 - res = source.multicast(observable);
     * 2 - res = source.multicast(function () { return new Subject(); }, function (x) { return x; });
     *
     * @param {Function|Subject} subjectOrSubjectSelector
     * Factory function to create an intermediate subject through which the source sequence's elements will be multicast to the selector function.
     * Or:
     * Subject to push source elements into.
     *
     * @param {Function} [selector] Optional selector function which can use the multicasted source sequence subject to the policies enforced by the created subject. Specified only if <paramref name="subjectOrSubjectSelector" is a factory function.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.
     */
    observableProto.multicast = function (subjectOrSubjectSelector, selector) {
        return isFunction(subjectOrSubjectSelector) ?
          new MulticastObservable(this, subjectOrSubjectSelector, selector) :
          new ConnectableObservable(this, subjectOrSubjectSelector);
    };

    /**
     * Returns an observable sequence that is the result of invoking the selector on a connectable observable sequence that shares a single subscription to the underlying sequence.
     * This operator is a specialization of Multicast using a regular Subject.
     *
     * @example
     * var resres = source.publish();
     * var res = source.publish(function (x) { return x; });
     *
     * @param {Function} [selector] Selector function which can use the multicasted source sequence as many times as needed, without causing multiple subscriptions to the source sequence. Subscribers to the given source will receive all notifications of the source from the time of the subscription on.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.
     */
    observableProto.publish = function (selector) {
        return selector && isFunction(selector) ?
          this.multicast(function () { return new Subject(); }, selector) :
          this.multicast(new Subject());
    };

    /**
     * Returns an observable sequence that shares a single subscription to the underlying sequence.
     * This operator is a specialization of publish which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
     */
    observableProto.share = function () {
        return this.publish().refCount();
    };

    /**
     * Returns an observable sequence that is the result of invoking the selector on a connectable observable sequence that shares a single subscription to the underlying sequence containing only the last notification.
     * This operator is a specialization of Multicast using a AsyncSubject.
     *
     * @example
     * var res = source.publishLast();
     * var res = source.publishLast(function (x) { return x; });
     *
     * @param selector [Optional] Selector function which can use the multicasted source sequence as many times as needed, without causing multiple subscriptions to the source sequence. Subscribers to the given source will only receive the last notification of the source.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.
     */
    observableProto.publishLast = function (selector) {
        return selector && isFunction(selector) ?
          this.multicast(function () { return new AsyncSubject(); }, selector) :
          this.multicast(new AsyncSubject());
    };

    /**
     * Returns an observable sequence that is the result of invoking the selector on a connectable observable sequence that shares a single subscription to the underlying sequence and starts with initialValue.
     * This operator is a specialization of Multicast using a BehaviorSubject.
     *
     * @example
     * var res = source.publishValue(42);
     * var res = source.publishValue(function (x) { return x.select(function (y) { return y * y; }) }, 42);
     *
     * @param {Function} [selector] Optional selector function which can use the multicasted source sequence as many times as needed, without causing multiple subscriptions to the source sequence. Subscribers to the given source will receive immediately receive the initial value, followed by all notifications of the source from the time of the subscription on.
     * @param {Mixed} initialValue Initial value received by observers upon subscription.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.
     */
    observableProto.publishValue = function (initialValueOrSelector, initialValue) {
        return arguments.length === 2 ?
          this.multicast(function () {
              return new BehaviorSubject(initialValue);
          }, initialValueOrSelector) :
          this.multicast(new BehaviorSubject(initialValueOrSelector));
    };

    /**
     * Returns an observable sequence that shares a single subscription to the underlying sequence and starts with an initialValue.
     * This operator is a specialization of publishValue which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
     * @param {Mixed} initialValue Initial value received by observers upon subscription.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
     */
    observableProto.shareValue = function (initialValue) {
        return this.publishValue(initialValue).refCount();
    };

    /**
     * Returns an observable sequence that is the result of invoking the selector on a connectable observable sequence that shares a single subscription to the underlying sequence replaying notifications subject to a maximum time length for the replay buffer.
     * This operator is a specialization of Multicast using a ReplaySubject.
     *
     * @example
     * var res = source.replay(null, 3);
     * var res = source.replay(null, 3, 500);
     * var res = source.replay(null, 3, 500, scheduler);
     * var res = source.replay(function (x) { return x.take(6).repeat(); }, 3, 500, scheduler);
     *
     * @param selector [Optional] Selector function which can use the multicasted source sequence as many times as needed, without causing multiple subscriptions to the source sequence. Subscribers to the given source will receive all the notifications of the source subject to the specified replay buffer trimming policy.
     * @param bufferSize [Optional] Maximum element count of the replay buffer.
     * @param windowSize [Optional] Maximum time length of the replay buffer.
     * @param scheduler [Optional] Scheduler where connected observers within the selector function will be invoked on.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.
     */
    observableProto.replay = function (selector, bufferSize, windowSize, scheduler) {
        return selector && isFunction(selector) ?
          this.multicast(function () { return new ReplaySubject(bufferSize, windowSize, scheduler); }, selector) :
          this.multicast(new ReplaySubject(bufferSize, windowSize, scheduler));
    };

    /**
     * Returns an observable sequence that shares a single subscription to the underlying sequence replaying notifications subject to a maximum time length for the replay buffer.
     * This operator is a specialization of replay which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
     *
     * @example
     * var res = source.shareReplay(3);
     * var res = source.shareReplay(3, 500);
     * var res = source.shareReplay(3, 500, scheduler);
     *
  
     * @param bufferSize [Optional] Maximum element count of the replay buffer.
     * @param window [Optional] Maximum time length of the replay buffer.
     * @param scheduler [Optional] Scheduler where connected observers within the selector function will be invoked on.
     * @returns {Observable} An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
     */
    observableProto.shareReplay = function (bufferSize, windowSize, scheduler) {
        return this.replay(null, bufferSize, windowSize, scheduler).refCount();
    };

    var RefCountObservable = (function (__super__) {
        inherits(RefCountObservable, __super__);
        function RefCountObservable(source) {
            this.source = source;
            this._count = 0;
            this._connectableSubscription = null;
            __super__.call(this);
        }

        RefCountObservable.prototype.subscribeCore = function (o) {
            var subscription = this.source.subscribe(o);
            ++this._count === 1 && (this._connectableSubscription = this.source.connect());
            return new RefCountDisposable(this, subscription);
        };

        function RefCountDisposable(p, s) {
            this._p = p;
            this._s = s;
            this.isDisposed = false;
        }

        RefCountDisposable.prototype.dispose = function () {
            if (!this.isDisposed) {
                this.isDisposed = true;
                this._s.dispose();
                --this._p._count === 0 && this._p._connectableSubscription.dispose();
            }
        };

        return RefCountObservable;
    }(ObservableBase));

    var ConnectableObservable = Rx.ConnectableObservable = (function (__super__) {
        inherits(ConnectableObservable, __super__);
        function ConnectableObservable(source, subject) {
            this.source = source;
            this._connection = null;
            this._source = source.asObservable();
            this._subject = subject;
            __super__.call(this);
        }

        function ConnectDisposable(parent, subscription) {
            this._p = parent;
            this._s = subscription;
        }

        ConnectDisposable.prototype.dispose = function () {
            if (this._s) {
                this._s.dispose();
                this._s = null;
                this._p._connection = null;
            }
        };

        ConnectableObservable.prototype.connect = function () {
            if (!this._connection) {
                if (this._subject.isStopped) {
                    return disposableEmpty;
                }
                var subscription = this._source.subscribe(this._subject);
                this._connection = new ConnectDisposable(this, subscription);
            }
            return this._connection;
        };

        ConnectableObservable.prototype._subscribe = function (o) {
            return this._subject.subscribe(o);
        };

        ConnectableObservable.prototype.refCount = function () {
            return new RefCountObservable(this);
        };

        return ConnectableObservable;
    }(Observable));

    var TimerObservable = (function (__super__) {
        inherits(TimerObservable, __super__);
        function TimerObservable(dt, s) {
            this._dt = dt;
            this._s = s;
            __super__.call(this);
        }

        TimerObservable.prototype.subscribeCore = function (o) {
            return this._s.scheduleFuture(o, this._dt, scheduleMethod);
        };

        function scheduleMethod(s, o) {
            o.onNext(0);
            o.onCompleted();
        }

        return TimerObservable;
    }(ObservableBase));

    function _observableTimer(dueTime, scheduler) {
        return new TimerObservable(dueTime, scheduler);
    }

    function observableTimerDateAndPeriod(dueTime, period, scheduler) {
        return new AnonymousObservable(function (observer) {
            var d = dueTime, p = normalizeTime(period);
            return scheduler.scheduleRecursiveFuture(0, d, function (count, self) {
                if (p > 0) {
                    var now = scheduler.now();
                    d = new Date(d.getTime() + p);
                    d.getTime() <= now && (d = new Date(now + p));
                }
                observer.onNext(count);
                self(count + 1, new Date(d));
            });
        });
    }

    function observableTimerTimeSpanAndPeriod(dueTime, period, scheduler) {
        return dueTime === period ?
          new AnonymousObservable(function (observer) {
              return scheduler.schedulePeriodic(0, period, function (count) {
                  observer.onNext(count);
                  return count + 1;
              });
          }) :
          observableDefer(function () {
              return observableTimerDateAndPeriod(new Date(scheduler.now() + dueTime), period, scheduler);
          });
    }

    /**
     *  Returns an observable sequence that produces a value after each period.
     *
     * @example
     *  1 - res = Rx.Observable.interval(1000);
     *  2 - res = Rx.Observable.interval(1000, Rx.Scheduler.timeout);
     *
     * @param {Number} period Period for producing the values in the resulting sequence (specified as an integer denoting milliseconds).
     * @param {Scheduler} [scheduler] Scheduler to run the timer on. If not specified, Rx.Scheduler.timeout is used.
     * @returns {Observable} An observable sequence that produces a value after each period.
     */
    var observableinterval = Observable.interval = function (period, scheduler) {
        return observableTimerTimeSpanAndPeriod(period, period, isScheduler(scheduler) ? scheduler : defaultScheduler);
    };

    /**
     *  Returns an observable sequence that produces a value after dueTime has elapsed and then after each period.
     * @param {Number} dueTime Absolute (specified as a Date object) or relative time (specified as an integer denoting milliseconds) at which to produce the first value.
     * @param {Mixed} [periodOrScheduler]  Period to produce subsequent values (specified as an integer denoting milliseconds), or the scheduler to run the timer on. If not specified, the resulting timer is not recurring.
     * @param {Scheduler} [scheduler]  Scheduler to run the timer on. If not specified, the timeout scheduler is used.
     * @returns {Observable} An observable sequence that produces a value after due time has elapsed and then each period.
     */
    var observableTimer = Observable.timer = function (dueTime, periodOrScheduler, scheduler) {
        var period;
        isScheduler(scheduler) || (scheduler = defaultScheduler);
        if (periodOrScheduler != null && typeof periodOrScheduler === 'number') {
            period = periodOrScheduler;
        } else if (isScheduler(periodOrScheduler)) {
            scheduler = periodOrScheduler;
        }
        if ((dueTime instanceof Date || typeof dueTime === 'number') && period === undefined) {
            return _observableTimer(dueTime, scheduler);
        }
        if (dueTime instanceof Date && period !== undefined) {
            return observableTimerDateAndPeriod(dueTime, periodOrScheduler, scheduler);
        }
        return observableTimerTimeSpanAndPeriod(dueTime, period, scheduler);
    };

    function observableDelayRelative(source, dueTime, scheduler) {
        return new AnonymousObservable(function (o) {
            var active = false,
              cancelable = new SerialDisposable(),
              exception = null,
              q = [],
              running = false,
              subscription;
            subscription = source.materialize().timestamp(scheduler).subscribe(function (notification) {
                var d, shouldRun;
                if (notification.value.kind === 'E') {
                    q = [];
                    q.push(notification);
                    exception = notification.value.error;
                    shouldRun = !running;
                } else {
                    q.push({ value: notification.value, timestamp: notification.timestamp + dueTime });
                    shouldRun = !active;
                    active = true;
                }
                if (shouldRun) {
                    if (exception !== null) {
                        o.onError(exception);
                    } else {
                        d = new SingleAssignmentDisposable();
                        cancelable.setDisposable(d);
                        d.setDisposable(scheduler.scheduleRecursiveFuture(null, dueTime, function (_, self) {
                            var e, recurseDueTime, result, shouldRecurse;
                            if (exception !== null) {
                                return;
                            }
                            running = true;
                            do {
                                result = null;
                                if (q.length > 0 && q[0].timestamp - scheduler.now() <= 0) {
                                    result = q.shift().value;
                                }
                                if (result !== null) {
                                    result.accept(o);
                                }
                            } while (result !== null);
                            shouldRecurse = false;
                            recurseDueTime = 0;
                            if (q.length > 0) {
                                shouldRecurse = true;
                                recurseDueTime = Math.max(0, q[0].timestamp - scheduler.now());
                            } else {
                                active = false;
                            }
                            e = exception;
                            running = false;
                            if (e !== null) {
                                o.onError(e);
                            } else if (shouldRecurse) {
                                self(null, recurseDueTime);
                            }
                        }));
                    }
                }
            });
            return new BinaryDisposable(subscription, cancelable);
        }, source);
    }

    function observableDelayAbsolute(source, dueTime, scheduler) {
        return observableDefer(function () {
            return observableDelayRelative(source, dueTime - scheduler.now(), scheduler);
        });
    }

    function delayWithSelector(source, subscriptionDelay, delayDurationSelector) {
        var subDelay, selector;
        if (isFunction(subscriptionDelay)) {
            selector = subscriptionDelay;
        } else {
            subDelay = subscriptionDelay;
            selector = delayDurationSelector;
        }
        return new AnonymousObservable(function (o) {
            var delays = new CompositeDisposable(), atEnd = false, subscription = new SerialDisposable();

            function start() {
                subscription.setDisposable(source.subscribe(
                  function (x) {
                      var delay = tryCatch(selector)(x);
                      if (delay === errorObj) { return o.onError(delay.e); }
                      var d = new SingleAssignmentDisposable();
                      delays.add(d);
                      d.setDisposable(delay.subscribe(
                        function () {
                            o.onNext(x);
                            delays.remove(d);
                            done();
                        },
                        function (e) { o.onError(e); },
                        function () {
                            o.onNext(x);
                            delays.remove(d);
                            done();
                        }
                      ));
                  },
                  function (e) { o.onError(e); },
                  function () {
                      atEnd = true;
                      subscription.dispose();
                      done();
                  }
                ));
            }

            function done() {
                atEnd && delays.length === 0 && o.onCompleted();
            }

            if (!subDelay) {
                start();
            } else {
                subscription.setDisposable(subDelay.subscribe(start, function (e) { o.onError(e); }, start));
            }

            return new BinaryDisposable(subscription, delays);
        }, source);
    }

    /**
     *  Time shifts the observable sequence by dueTime.
     *  The relative time intervals between the values are preserved.
     *
     * @param {Number} dueTime Absolute (specified as a Date object) or relative time (specified as an integer denoting milliseconds) by which to shift the observable sequence.
     * @param {Scheduler} [scheduler] Scheduler to run the delay timers on. If not specified, the timeout scheduler is used.
     * @returns {Observable} Time-shifted sequence.
     */
    observableProto.delay = function () {
        var firstArg = arguments[0];
        if (typeof firstArg === 'number' || firstArg instanceof Date) {
            var dueTime = firstArg, scheduler = arguments[1];
            isScheduler(scheduler) || (scheduler = defaultScheduler);
            return dueTime instanceof Date ?
              observableDelayAbsolute(this, dueTime, scheduler) :
              observableDelayRelative(this, dueTime, scheduler);
        } else if (Observable.isObservable(firstArg) || isFunction(firstArg)) {
            return delayWithSelector(this, firstArg, arguments[1]);
        } else {
            throw new Error('Invalid arguments');
        }
    };

    var DebounceObservable = (function (__super__) {
        inherits(DebounceObservable, __super__);
        function DebounceObservable(source, dt, s) {
            isScheduler(s) || (s = defaultScheduler);
            this.source = source;
            this._dt = dt;
            this._s = s;
            __super__.call(this);
        }

        DebounceObservable.prototype.subscribeCore = function (o) {
            var cancelable = new SerialDisposable();
            return new BinaryDisposable(
              this.source.subscribe(new DebounceObserver(o, this._dt, this._s, cancelable)),
              cancelable);
        };

        return DebounceObservable;
    }(ObservableBase));

    var DebounceObserver = (function (__super__) {
        inherits(DebounceObserver, __super__);
        function DebounceObserver(observer, dueTime, scheduler, cancelable) {
            this._o = observer;
            this._d = dueTime;
            this._scheduler = scheduler;
            this._c = cancelable;
            this._v = null;
            this._hv = false;
            this._id = 0;
            __super__.call(this);
        }

        function scheduleFuture(s, state) {
            state.self._hv && state.self._id === state.currentId && state.self._o.onNext(state.x);
            state.self._hv = false;
        }

        DebounceObserver.prototype.next = function (x) {
            this._hv = true;
            this._v = x;
            var currentId = ++this._id, d = new SingleAssignmentDisposable();
            this._c.setDisposable(d);
            d.setDisposable(this._scheduler.scheduleFuture(this, this._d, function (_, self) {
                self._hv && self._id === currentId && self._o.onNext(x);
                self._hv = false;
            }));
        };

        DebounceObserver.prototype.error = function (e) {
            this._c.dispose();
            this._o.onError(e);
            this._hv = false;
            this._id++;
        };

        DebounceObserver.prototype.completed = function () {
            this._c.dispose();
            this._hv && this._o.onNext(this._v);
            this._o.onCompleted();
            this._hv = false;
            this._id++;
        };

        return DebounceObserver;
    }(AbstractObserver));

    function debounceWithSelector(source, durationSelector) {
        return new AnonymousObservable(function (o) {
            var value, hasValue = false, cancelable = new SerialDisposable(), id = 0;
            var subscription = source.subscribe(
              function (x) {
                  var throttle = tryCatch(durationSelector)(x);
                  if (throttle === errorObj) { return o.onError(throttle.e); }

                  isPromise(throttle) && (throttle = observableFromPromise(throttle));

                  hasValue = true;
                  value = x;
                  id++;
                  var currentid = id, d = new SingleAssignmentDisposable();
                  cancelable.setDisposable(d);
                  d.setDisposable(throttle.subscribe(
                    function () {
                        hasValue && id === currentid && o.onNext(value);
                        hasValue = false;
                        d.dispose();
                    },
                    function (e) { o.onError(e); },
                    function () {
                        hasValue && id === currentid && o.onNext(value);
                        hasValue = false;
                        d.dispose();
                    }
                  ));
              },
              function (e) {
                  cancelable.dispose();
                  o.onError(e);
                  hasValue = false;
                  id++;
              },
              function () {
                  cancelable.dispose();
                  hasValue && o.onNext(value);
                  o.onCompleted();
                  hasValue = false;
                  id++;
              }
            );
            return new BinaryDisposable(subscription, cancelable);
        }, source);
    }

    observableProto.debounce = function () {
        if (isFunction(arguments[0])) {
            return debounceWithSelector(this, arguments[0]);
        } else if (typeof arguments[0] === 'number') {
            return new DebounceObservable(this, arguments[0], arguments[1]);
        } else {
            throw new Error('Invalid arguments');
        }
    };

    var TimestampObservable = (function (__super__) {
        inherits(TimestampObservable, __super__);
        function TimestampObservable(source, s) {
            this.source = source;
            this._s = s;
            __super__.call(this);
        }

        TimestampObservable.prototype.subscribeCore = function (o) {
            return this.source.subscribe(new TimestampObserver(o, this._s));
        };

        return TimestampObservable;
    }(ObservableBase));

    var TimestampObserver = (function (__super__) {
        inherits(TimestampObserver, __super__);
        function TimestampObserver(o, s) {
            this._o = o;
            this._s = s;
            __super__.call(this);
        }

        TimestampObserver.prototype.next = function (x) {
            this._o.onNext({ value: x, timestamp: this._s.now() });
        };

        TimestampObserver.prototype.error = function (e) {
            this._o.onError(e);
        };

        TimestampObserver.prototype.completed = function () {
            this._o.onCompleted();
        };

        return TimestampObserver;
    }(AbstractObserver));

    /**
     *  Records the timestamp for each value in an observable sequence.
     *
     * @example
     *  1 - res = source.timestamp(); // produces { value: x, timestamp: ts }
     *  2 - res = source.timestamp(Rx.Scheduler.default);
     *
     * @param {Scheduler} [scheduler]  Scheduler used to compute timestamps. If not specified, the default scheduler is used.
     * @returns {Observable} An observable sequence with timestamp information on values.
     */
    observableProto.timestamp = function (scheduler) {
        isScheduler(scheduler) || (scheduler = defaultScheduler);
        return new TimestampObservable(this, scheduler);
    };

    var SampleObservable = (function (__super__) {
        inherits(SampleObservable, __super__);
        function SampleObservable(source, sampler) {
            this.source = source;
            this._sampler = sampler;
            __super__.call(this);
        }

        SampleObservable.prototype.subscribeCore = function (o) {
            var state = {
                o: o,
                atEnd: false,
                value: null,
                hasValue: false,
                sourceSubscription: new SingleAssignmentDisposable()
            };

            state.sourceSubscription.setDisposable(this.source.subscribe(new SampleSourceObserver(state)));
            return new BinaryDisposable(
              state.sourceSubscription,
              this._sampler.subscribe(new SamplerObserver(state))
            );
        };

        return SampleObservable;
    }(ObservableBase));

    var SamplerObserver = (function (__super__) {
        inherits(SamplerObserver, __super__);
        function SamplerObserver(s) {
            this._s = s;
            __super__.call(this);
        }

        SamplerObserver.prototype._handleMessage = function () {
            if (this._s.hasValue) {
                this._s.hasValue = false;
                this._s.o.onNext(this._s.value);
            }
            this._s.atEnd && this._s.o.onCompleted();
        };

        SamplerObserver.prototype.next = function () { this._handleMessage(); };
        SamplerObserver.prototype.error = function (e) { this._s.onError(e); };
        SamplerObserver.prototype.completed = function () { this._handleMessage(); };

        return SamplerObserver;
    }(AbstractObserver));

    var SampleSourceObserver = (function (__super__) {
        inherits(SampleSourceObserver, __super__);
        function SampleSourceObserver(s) {
            this._s = s;
            __super__.call(this);
        }

        SampleSourceObserver.prototype.next = function (x) {
            this._s.hasValue = true;
            this._s.value = x;
        };
        SampleSourceObserver.prototype.error = function (e) { this._s.o.onError(e); };
        SampleSourceObserver.prototype.completed = function () {
            this._s.atEnd = true;
            this._s.sourceSubscription.dispose();
        };

        return SampleSourceObserver;
    }(AbstractObserver));

    /**
     *  Samples the observable sequence at each interval.
     *
     * @example
     *  1 - res = source.sample(sampleObservable); // Sampler tick sequence
     *  2 - res = source.sample(5000); // 5 seconds
     *  2 - res = source.sample(5000, Rx.Scheduler.timeout); // 5 seconds
     *
     * @param {Mixed} intervalOrSampler Interval at which to sample (specified as an integer denoting milliseconds) or Sampler Observable.
     * @param {Scheduler} [scheduler]  Scheduler to run the sampling timer on. If not specified, the timeout scheduler is used.
     * @returns {Observable} Sampled observable sequence.
     */
    observableProto.sample = function (intervalOrSampler, scheduler) {
        isScheduler(scheduler) || (scheduler = defaultScheduler);
        return typeof intervalOrSampler === 'number' ?
          new SampleObservable(this, observableinterval(intervalOrSampler, scheduler)) :
          new SampleObservable(this, intervalOrSampler);
    };

    var TimeoutError = Rx.TimeoutError = function (message) {
        this.message = message || 'Timeout has occurred';
        this.name = 'TimeoutError';
        Error.call(this);
    };
    TimeoutError.prototype = Object.create(Error.prototype);

    function timeoutWithSelector(source, firstTimeout, timeoutDurationSelector, other) {
        if (isFunction(firstTimeout)) {
            other = timeoutDurationSelector;
            timeoutDurationSelector = firstTimeout;
            firstTimeout = observableNever();
        }
        Observable.isObservable(other) || (other = observableThrow(new TimeoutError()));
        return new AnonymousObservable(function (o) {
            var subscription = new SerialDisposable(),
              timer = new SerialDisposable(),
              original = new SingleAssignmentDisposable();

            subscription.setDisposable(original);

            var id = 0, switched = false;

            function setTimer(timeout) {
                var myId = id, d = new SingleAssignmentDisposable();

                function timerWins() {
                    switched = (myId === id);
                    return switched;
                }

                timer.setDisposable(d);
                d.setDisposable(timeout.subscribe(function () {
                    timerWins() && subscription.setDisposable(other.subscribe(o));
                    d.dispose();
                }, function (e) {
                    timerWins() && o.onError(e);
                }, function () {
                    timerWins() && subscription.setDisposable(other.subscribe(o));
                }));
            };

            setTimer(firstTimeout);

            function oWins() {
                var res = !switched;
                if (res) { id++; }
                return res;
            }

            original.setDisposable(source.subscribe(function (x) {
                if (oWins()) {
                    o.onNext(x);
                    var timeout = tryCatch(timeoutDurationSelector)(x);
                    if (timeout === errorObj) { return o.onError(timeout.e); }
                    setTimer(isPromise(timeout) ? observableFromPromise(timeout) : timeout);
                }
            }, function (e) {
                oWins() && o.onError(e);
            }, function () {
                oWins() && o.onCompleted();
            }));
            return new BinaryDisposable(subscription, timer);
        }, source);
    }

    function timeout(source, dueTime, other, scheduler) {
        if (isScheduler(other)) {
            scheduler = other;
            other = observableThrow(new TimeoutError());
        }
        if (other instanceof Error) { other = observableThrow(other); }
        isScheduler(scheduler) || (scheduler = defaultScheduler);
        Observable.isObservable(other) || (other = observableThrow(new TimeoutError()));
        return new AnonymousObservable(function (o) {
            var id = 0,
              original = new SingleAssignmentDisposable(),
              subscription = new SerialDisposable(),
              switched = false,
              timer = new SerialDisposable();

            subscription.setDisposable(original);

            function createTimer() {
                var myId = id;
                timer.setDisposable(scheduler.scheduleFuture(null, dueTime, function () {
                    switched = id === myId;
                    if (switched) {
                        isPromise(other) && (other = observableFromPromise(other));
                        subscription.setDisposable(other.subscribe(o));
                    }
                }));
            }

            createTimer();

            original.setDisposable(source.subscribe(function (x) {
                if (!switched) {
                    id++;
                    o.onNext(x);
                    createTimer();
                }
            }, function (e) {
                if (!switched) {
                    id++;
                    o.onError(e);
                }
            }, function () {
                if (!switched) {
                    id++;
                    o.onCompleted();
                }
            }));
            return new BinaryDisposable(subscription, timer);
        }, source);
    }

    observableProto.timeout = function () {
        var firstArg = arguments[0];
        if (firstArg instanceof Date || typeof firstArg === 'number') {
            return timeout(this, firstArg, arguments[1], arguments[2]);
        } else if (Observable.isObservable(firstArg) || isFunction(firstArg)) {
            return timeoutWithSelector(this, firstArg, arguments[1], arguments[2]);
        } else {
            throw new Error('Invalid arguments');
        }
    };

    /**
     * Returns an Observable that emits only the first item emitted by the source Observable during sequential time windows of a specified duration.
     * @param {Number} windowDuration time to wait before emitting another item after emitting the last item
     * @param {Scheduler} [scheduler] the Scheduler to use internally to manage the timers that handle timeout for each item. If not provided, defaults to Scheduler.timeout.
     * @returns {Observable} An Observable that performs the throttle operation.
     */
    observableProto.throttle = function (windowDuration, scheduler) {
        isScheduler(scheduler) || (scheduler = defaultScheduler);
        var duration = +windowDuration || 0;
        if (duration <= 0) { throw new RangeError('windowDuration cannot be less or equal zero.'); }
        var source = this;
        return new AnonymousObservable(function (o) {
            var lastOnNext = 0;
            return source.subscribe(
              function (x) {
                  var now = scheduler.now();
                  if (lastOnNext === 0 || now - lastOnNext >= duration) {
                      lastOnNext = now;
                      o.onNext(x);
                  }
              }, function (e) { o.onError(e); }, function () { o.onCompleted(); }
            );
        }, source);
    };

    var PausableObservable = (function (__super__) {
        inherits(PausableObservable, __super__);
        function PausableObservable(source, pauser) {
            this.source = source;
            this.controller = new Subject();
            this.paused = true;

            if (pauser && pauser.subscribe) {
                this.pauser = this.controller.merge(pauser);
            } else {
                this.pauser = this.controller;
            }

            __super__.call(this);
        }

        PausableObservable.prototype._subscribe = function (o) {
            var conn = this.source.publish(),
              subscription = conn.subscribe(o),
              connection = disposableEmpty;

            var pausable = this.pauser.startWith(!this.paused).distinctUntilChanged().subscribe(function (b) {
                if (b) {
                    connection = conn.connect();
                } else {
                    connection.dispose();
                    connection = disposableEmpty;
                }
            });

            return new NAryDisposable([subscription, connection, pausable]);
        };

        PausableObservable.prototype.pause = function () {
            this.paused = true;
            this.controller.onNext(false);
        };

        PausableObservable.prototype.resume = function () {
            this.paused = false;
            this.controller.onNext(true);
        };

        return PausableObservable;

    }(Observable));

    /**
     * Pauses the underlying observable sequence based upon the observable sequence which yields true/false.
     * @example
     * var pauser = new Rx.Subject();
     * var source = Rx.Observable.interval(100).pausable(pauser);
     * @param {Observable} pauser The observable sequence used to pause the underlying sequence.
     * @returns {Observable} The observable sequence which is paused based upon the pauser.
     */
    observableProto.pausable = function (pauser) {
        return new PausableObservable(this, pauser);
    };

    function combineLatestSource(source, subject, resultSelector) {
        return new AnonymousObservable(function (o) {
            var hasValue = [false, false],
              hasValueAll = false,
              isDone = false,
              values = new Array(2),
              err;

            function next(x, i) {
                values[i] = x;
                hasValue[i] = true;
                if (hasValueAll || (hasValueAll = hasValue.every(identity))) {
                    if (err) { return o.onError(err); }
                    var res = tryCatch(resultSelector).apply(null, values);
                    if (res === errorObj) { return o.onError(res.e); }
                    o.onNext(res);
                }
                isDone && values[1] && o.onCompleted();
            }

            return new BinaryDisposable(
              source.subscribe(
                function (x) {
                    next(x, 0);
                },
                function (e) {
                    if (values[1]) {
                        o.onError(e);
                    } else {
                        err = e;
                    }
                },
                function () {
                    isDone = true;
                    values[1] && o.onCompleted();
                }),
              subject.subscribe(
                function (x) {
                    next(x, 1);
                },
                function (e) { o.onError(e); },
                function () {
                    isDone = true;
                    next(true, 1);
                })
              );
        }, source);
    }

    var PausableBufferedObservable = (function (__super__) {
        inherits(PausableBufferedObservable, __super__);
        function PausableBufferedObservable(source, pauser) {
            this.source = source;
            this.controller = new Subject();
            this.paused = true;

            if (pauser && pauser.subscribe) {
                this.pauser = this.controller.merge(pauser);
            } else {
                this.pauser = this.controller;
            }

            __super__.call(this);
        }

        PausableBufferedObservable.prototype._subscribe = function (o) {
            var q = [], previousShouldFire;

            function drainQueue() { while (q.length > 0) { o.onNext(q.shift()); } }

            var subscription =
              combineLatestSource(
                this.source,
                this.pauser.startWith(!this.paused).distinctUntilChanged(),
                function (data, shouldFire) {
                    return { data: data, shouldFire: shouldFire };
                })
                .subscribe(
                  function (results) {
                      if (previousShouldFire !== undefined && results.shouldFire !== previousShouldFire) {
                          previousShouldFire = results.shouldFire;
                          // change in shouldFire
                          if (results.shouldFire) { drainQueue(); }
                      } else {
                          previousShouldFire = results.shouldFire;
                          // new data
                          if (results.shouldFire) {
                              o.onNext(results.data);
                          } else {
                              q.push(results.data);
                          }
                      }
                  },
                  function (err) {
                      drainQueue();
                      o.onError(err);
                  },
                  function () {
                      drainQueue();
                      o.onCompleted();
                  }
                );
            return subscription;
        };

        PausableBufferedObservable.prototype.pause = function () {
            this.paused = true;
            this.controller.onNext(false);
        };

        PausableBufferedObservable.prototype.resume = function () {
            this.paused = false;
            this.controller.onNext(true);
        };

        return PausableBufferedObservable;

    }(Observable));

    /**
     * Pauses the underlying observable sequence based upon the observable sequence which yields true/false,
     * and yields the values that were buffered while paused.
     * @example
     * var pauser = new Rx.Subject();
     * var source = Rx.Observable.interval(100).pausableBuffered(pauser);
     * @param {Observable} pauser The observable sequence used to pause the underlying sequence.
     * @returns {Observable} The observable sequence which is paused based upon the pauser.
     */
    observableProto.pausableBuffered = function (pauser) {
        return new PausableBufferedObservable(this, pauser);
    };

    var ControlledObservable = (function (__super__) {
        inherits(ControlledObservable, __super__);
        function ControlledObservable(source, enableQueue, scheduler) {
            __super__.call(this);
            this.subject = new ControlledSubject(enableQueue, scheduler);
            this.source = source.multicast(this.subject).refCount();
        }

        ControlledObservable.prototype._subscribe = function (o) {
            return this.source.subscribe(o);
        };

        ControlledObservable.prototype.request = function (numberOfItems) {
            return this.subject.request(numberOfItems == null ? -1 : numberOfItems);
        };

        return ControlledObservable;

    }(Observable));

    var ControlledSubject = (function (__super__) {
        inherits(ControlledSubject, __super__);
        function ControlledSubject(enableQueue, scheduler) {
            enableQueue == null && (enableQueue = true);

            __super__.call(this);
            this.subject = new Subject();
            this.enableQueue = enableQueue;
            this.queue = enableQueue ? [] : null;
            this.requestedCount = 0;
            this.requestedDisposable = null;
            this.error = null;
            this.hasFailed = false;
            this.hasCompleted = false;
            this.scheduler = scheduler || currentThreadScheduler;
        }

        addProperties(ControlledSubject.prototype, Observer, {
            _subscribe: function (o) {
                return this.subject.subscribe(o);
            },
            onCompleted: function () {
                this.hasCompleted = true;
                if (!this.enableQueue || this.queue.length === 0) {
                    this.subject.onCompleted();
                    this.disposeCurrentRequest();
                } else {
                    this.queue.push(Notification.createOnCompleted());
                }
            },
            onError: function (error) {
                this.hasFailed = true;
                this.error = error;
                if (!this.enableQueue || this.queue.length === 0) {
                    this.subject.onError(error);
                    this.disposeCurrentRequest();
                } else {
                    this.queue.push(Notification.createOnError(error));
                }
            },
            onNext: function (value) {
                if (this.requestedCount <= 0) {
                    this.enableQueue && this.queue.push(Notification.createOnNext(value));
                } else {
                    (this.requestedCount-- === 0) && this.disposeCurrentRequest();
                    this.subject.onNext(value);
                }
            },
            _processRequest: function (numberOfItems) {
                if (this.enableQueue) {
                    while (this.queue.length > 0 && (numberOfItems > 0 || this.queue[0].kind !== 'N')) {
                        var first = this.queue.shift();
                        first.accept(this.subject);
                        if (first.kind === 'N') {
                            numberOfItems--;
                        } else {
                            this.disposeCurrentRequest();
                            this.queue = [];
                        }
                    }
                }

                return numberOfItems;
            },
            request: function (number) {
                this.disposeCurrentRequest();
                var self = this;

                this.requestedDisposable = this.scheduler.schedule(number,
                function (s, i) {
                    var remaining = self._processRequest(i);
                    var stopped = self.hasCompleted || self.hasFailed;
                    if (!stopped && remaining > 0) {
                        self.requestedCount = remaining;

                        return disposableCreate(function () {
                            self.requestedCount = 0;
                        });
                        // Scheduled item is still in progress. Return a new
                        // disposable to allow the request to be interrupted
                        // via dispose.
                    }
                });

                return this.requestedDisposable;
            },
            disposeCurrentRequest: function () {
                if (this.requestedDisposable) {
                    this.requestedDisposable.dispose();
                    this.requestedDisposable = null;
                }
            }
        });

        return ControlledSubject;
    }(Observable));

    /**
     * Attaches a controller to the observable sequence with the ability to queue.
     * @example
     * var source = Rx.Observable.interval(100).controlled();
     * source.request(3); // Reads 3 values
     * @param {bool} enableQueue truthy value to determine if values should be queued pending the next request
     * @param {Scheduler} scheduler determines how the requests will be scheduled
     * @returns {Observable} The observable sequence which only propagates values on request.
     */
    observableProto.controlled = function (enableQueue, scheduler) {

        if (enableQueue && isScheduler(enableQueue)) {
            scheduler = enableQueue;
            enableQueue = true;
        }

        if (enableQueue == null) { enableQueue = true; }
        return new ControlledObservable(this, enableQueue, scheduler);
    };

    /**
     * Pipes the existing Observable sequence into a Node.js Stream.
     * @param {Stream} dest The destination Node.js stream.
     * @returns {Stream} The destination stream.
     */
    observableProto.pipe = function (dest) {
        var source = this.pausableBuffered();

        function onDrain() {
            source.resume();
        }

        dest.addListener('drain', onDrain);

        source.subscribe(
          function (x) {
              !dest.write(x) && source.pause();
          },
          function (err) {
              dest.emit('error', err);
          },
          function () {
              // Hack check because STDIO is not closable
              !dest._isStdio && dest.end();
              dest.removeListener('drain', onDrain);
          });

        source.resume();

        return dest;
    };

    var TransduceObserver = (function (__super__) {
        inherits(TransduceObserver, __super__);
        function TransduceObserver(o, xform) {
            this._o = o;
            this._xform = xform;
            __super__.call(this);
        }

        TransduceObserver.prototype.next = function (x) {
            var res = tryCatch(this._xform['@@transducer/step']).call(this._xform, this._o, x);
            if (res === errorObj) { this._o.onError(res.e); }
        };

        TransduceObserver.prototype.error = function (e) { this._o.onError(e); };

        TransduceObserver.prototype.completed = function () {
            this._xform['@@transducer/result'](this._o);
        };

        return TransduceObserver;
    }(AbstractObserver));

    function transformForObserver(o) {
        return {
            '@@transducer/init': function () {
                return o;
            },
            '@@transducer/step': function (obs, input) {
                return obs.onNext(input);
            },
            '@@transducer/result': function (obs) {
                return obs.onCompleted();
            }
        };
    }

    /**
     * Executes a transducer to transform the observable sequence
     * @param {Transducer} transducer A transducer to execute
     * @returns {Observable} An Observable sequence containing the results from the transducer.
     */
    observableProto.transduce = function (transducer) {
        var source = this;
        return new AnonymousObservable(function (o) {
            var xform = transducer(transformForObserver(o));
            return source.subscribe(new TransduceObserver(o, xform));
        }, source);
    };

    var AnonymousObservable = Rx.AnonymousObservable = (function (__super__) {
        inherits(AnonymousObservable, __super__);

        // Fix subscriber to check for undefined or function returned to decorate as Disposable
        function fixSubscriber(subscriber) {
            return subscriber && isFunction(subscriber.dispose) ? subscriber :
              isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty;
        }

        function setDisposable(s, state) {
            var ado = state[0], self = state[1];
            var sub = tryCatch(self.__subscribe).call(self, ado);
            if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); }
            ado.setDisposable(fixSubscriber(sub));
        }

        function AnonymousObservable(subscribe, parent) {
            this.source = parent;
            this.__subscribe = subscribe;
            __super__.call(this);
        }

        AnonymousObservable.prototype._subscribe = function (o) {
            var ado = new AutoDetachObserver(o), state = [ado, this];

            if (currentThreadScheduler.scheduleRequired()) {
                currentThreadScheduler.schedule(state, setDisposable);
            } else {
                setDisposable(null, state);
            }
            return ado;
        };

        return AnonymousObservable;

    }(Observable));

    var AutoDetachObserver = (function (__super__) {
        inherits(AutoDetachObserver, __super__);

        function AutoDetachObserver(observer) {
            __super__.call(this);
            this.observer = observer;
            this.m = new SingleAssignmentDisposable();
        }

        var AutoDetachObserverPrototype = AutoDetachObserver.prototype;

        AutoDetachObserverPrototype.next = function (value) {
            var result = tryCatch(this.observer.onNext).call(this.observer, value);
            if (result === errorObj) {
                this.dispose();
                thrower(result.e);
            }
        };

        AutoDetachObserverPrototype.error = function (err) {
            var result = tryCatch(this.observer.onError).call(this.observer, err);
            this.dispose();
            result === errorObj && thrower(result.e);
        };

        AutoDetachObserverPrototype.completed = function () {
            var result = tryCatch(this.observer.onCompleted).call(this.observer);
            this.dispose();
            result === errorObj && thrower(result.e);
        };

        AutoDetachObserverPrototype.setDisposable = function (value) { this.m.setDisposable(value); };
        AutoDetachObserverPrototype.getDisposable = function () { return this.m.getDisposable(); };

        AutoDetachObserverPrototype.dispose = function () {
            __super__.prototype.dispose.call(this);
            this.m.dispose();
        };

        return AutoDetachObserver;
    }(AbstractObserver));

    var InnerSubscription = function (s, o) {
        this._s = s;
        this._o = o;
    };

    InnerSubscription.prototype.dispose = function () {
        if (!this._s.isDisposed && this._o !== null) {
            var idx = this._s.observers.indexOf(this._o);
            this._s.observers.splice(idx, 1);
            this._o = null;
        }
    };

    /**
     *  Represents an object that is both an observable sequence as well as an observer.
     *  Each notification is broadcasted to all subscribed observers.
     */
    var Subject = Rx.Subject = (function (__super__) {
        inherits(Subject, __super__);
        function Subject() {
            __super__.call(this);
            this.isDisposed = false;
            this.isStopped = false;
            this.observers = [];
            this.hasError = false;
        }

        addProperties(Subject.prototype, Observer.prototype, {
            _subscribe: function (o) {
                checkDisposed(this);
                if (!this.isStopped) {
                    this.observers.push(o);
                    return new InnerSubscription(this, o);
                }
                if (this.hasError) {
                    o.onError(this.error);
                    return disposableEmpty;
                }
                o.onCompleted();
                return disposableEmpty;
            },
            /**
             * Indicates whether the subject has observers subscribed to it.
             * @returns {Boolean} Indicates whether the subject has observers subscribed to it.
             */
            hasObservers: function () { checkDisposed(this); return this.observers.length > 0; },
            /**
             * Notifies all subscribed observers about the end of the sequence.
             */
            onCompleted: function () {
                checkDisposed(this);
                if (!this.isStopped) {
                    this.isStopped = true;
                    for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                        os[i].onCompleted();
                    }

                    this.observers.length = 0;
                }
            },
            /**
             * Notifies all subscribed observers about the exception.
             * @param {Mixed} error The exception to send to all observers.
             */
            onError: function (error) {
                checkDisposed(this);
                if (!this.isStopped) {
                    this.isStopped = true;
                    this.error = error;
                    this.hasError = true;
                    for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                        os[i].onError(error);
                    }

                    this.observers.length = 0;
                }
            },
            /**
             * Notifies all subscribed observers about the arrival of the specified element in the sequence.
             * @param {Mixed} value The value to send to all observers.
             */
            onNext: function (value) {
                checkDisposed(this);
                if (!this.isStopped) {
                    for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                        os[i].onNext(value);
                    }
                }
            },
            /**
             * Unsubscribe all observers and release resources.
             */
            dispose: function () {
                this.isDisposed = true;
                this.observers = null;
            }
        });

        /**
         * Creates a subject from the specified observer and observable.
         * @param {Observer} observer The observer used to send messages to the subject.
         * @param {Observable} observable The observable used to subscribe to messages sent from the subject.
         * @returns {Subject} Subject implemented using the given observer and observable.
         */
        Subject.create = function (observer, observable) {
            return new AnonymousSubject(observer, observable);
        };

        return Subject;
    }(Observable));

    /**
     *  Represents the result of an asynchronous operation.
     *  The last value before the OnCompleted notification, or the error received through OnError, is sent to all subscribed observers.
     */
    var AsyncSubject = Rx.AsyncSubject = (function (__super__) {
        inherits(AsyncSubject, __super__);

        /**
         * Creates a subject that can only receive one value and that value is cached for all future observations.
         * @constructor
         */
        function AsyncSubject() {
            __super__.call(this);
            this.isDisposed = false;
            this.isStopped = false;
            this.hasValue = false;
            this.observers = [];
            this.hasError = false;
        }

        addProperties(AsyncSubject.prototype, Observer.prototype, {
            _subscribe: function (o) {
                checkDisposed(this);

                if (!this.isStopped) {
                    this.observers.push(o);
                    return new InnerSubscription(this, o);
                }

                if (this.hasError) {
                    o.onError(this.error);
                } else if (this.hasValue) {
                    o.onNext(this.value);
                    o.onCompleted();
                } else {
                    o.onCompleted();
                }

                return disposableEmpty;
            },
            /**
             * Indicates whether the subject has observers subscribed to it.
             * @returns {Boolean} Indicates whether the subject has observers subscribed to it.
             */
            hasObservers: function () { checkDisposed(this); return this.observers.length > 0; },
            /**
             * Notifies all subscribed observers about the end of the sequence, also causing the last received value to be sent out (if any).
             */
            onCompleted: function () {
                var i, len;
                checkDisposed(this);
                if (!this.isStopped) {
                    this.isStopped = true;
                    var os = cloneArray(this.observers), len = os.length;

                    if (this.hasValue) {
                        for (i = 0; i < len; i++) {
                            var o = os[i];
                            o.onNext(this.value);
                            o.onCompleted();
                        }
                    } else {
                        for (i = 0; i < len; i++) {
                            os[i].onCompleted();
                        }
                    }

                    this.observers.length = 0;
                }
            },
            /**
             * Notifies all subscribed observers about the error.
             * @param {Mixed} error The Error to send to all observers.
             */
            onError: function (error) {
                checkDisposed(this);
                if (!this.isStopped) {
                    this.isStopped = true;
                    this.hasError = true;
                    this.error = error;

                    for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                        os[i].onError(error);
                    }

                    this.observers.length = 0;
                }
            },
            /**
             * Sends a value to the subject. The last value received before successful termination will be sent to all subscribed and future observers.
             * @param {Mixed} value The value to store in the subject.
             */
            onNext: function (value) {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.value = value;
                this.hasValue = true;
            },
            /**
             * Unsubscribe all observers and release resources.
             */
            dispose: function () {
                this.isDisposed = true;
                this.observers = null;
                this.error = null;
                this.value = null;
            }
        });

        return AsyncSubject;
    }(Observable));

    var AnonymousSubject = Rx.AnonymousSubject = (function (__super__) {
        inherits(AnonymousSubject, __super__);
        function AnonymousSubject(observer, observable) {
            this.observer = observer;
            this.observable = observable;
            __super__.call(this);
        }

        addProperties(AnonymousSubject.prototype, Observer.prototype, {
            _subscribe: function (o) {
                return this.observable.subscribe(o);
            },
            onCompleted: function () {
                this.observer.onCompleted();
            },
            onError: function (error) {
                this.observer.onError(error);
            },
            onNext: function (value) {
                this.observer.onNext(value);
            }
        });

        return AnonymousSubject;
    }(Observable));

    /**
     *  Represents a value that changes over time.
     *  Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications.
     */
    var BehaviorSubject = Rx.BehaviorSubject = (function (__super__) {
        inherits(BehaviorSubject, __super__);
        function BehaviorSubject(value) {
            __super__.call(this);
            this.value = value;
            this.observers = [];
            this.isDisposed = false;
            this.isStopped = false;
            this.hasError = false;
        }

        addProperties(BehaviorSubject.prototype, Observer.prototype, {
            _subscribe: function (o) {
                checkDisposed(this);
                if (!this.isStopped) {
                    this.observers.push(o);
                    o.onNext(this.value);
                    return new InnerSubscription(this, o);
                }
                if (this.hasError) {
                    o.onError(this.error);
                } else {
                    o.onCompleted();
                }
                return disposableEmpty;
            },
            /**
             * Gets the current value or throws an exception.
             * Value is frozen after onCompleted is called.
             * After onError is called always throws the specified exception.
             * An exception is always thrown after dispose is called.
             * @returns {Mixed} The initial value passed to the constructor until onNext is called; after which, the last value passed to onNext.
             */
            getValue: function () {
                checkDisposed(this);
                if (this.hasError) { thrower(this.error); }
                return this.value;
            },
            /**
             * Indicates whether the subject has observers subscribed to it.
             * @returns {Boolean} Indicates whether the subject has observers subscribed to it.
             */
            hasObservers: function () { checkDisposed(this); return this.observers.length > 0; },
            /**
             * Notifies all subscribed observers about the end of the sequence.
             */
            onCompleted: function () {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.isStopped = true;
                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    os[i].onCompleted();
                }

                this.observers.length = 0;
            },
            /**
             * Notifies all subscribed observers about the exception.
             * @param {Mixed} error The exception to send to all observers.
             */
            onError: function (error) {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.isStopped = true;
                this.hasError = true;
                this.error = error;

                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    os[i].onError(error);
                }

                this.observers.length = 0;
            },
            /**
             * Notifies all subscribed observers about the arrival of the specified element in the sequence.
             * @param {Mixed} value The value to send to all observers.
             */
            onNext: function (value) {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.value = value;
                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    os[i].onNext(value);
                }
            },
            /**
             * Unsubscribe all observers and release resources.
             */
            dispose: function () {
                this.isDisposed = true;
                this.observers = null;
                this.value = null;
                this.error = null;
            }
        });

        return BehaviorSubject;
    }(Observable));

    /**
     * Represents an object that is both an observable sequence as well as an observer.
     * Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies.
     */
    var ReplaySubject = Rx.ReplaySubject = (function (__super__) {

        var maxSafeInteger = Math.pow(2, 53) - 1;

        function createRemovableDisposable(subject, observer) {
            return disposableCreate(function () {
                observer.dispose();
                !subject.isDisposed && subject.observers.splice(subject.observers.indexOf(observer), 1);
            });
        }

        inherits(ReplaySubject, __super__);

        /**
         *  Initializes a new instance of the ReplaySubject class with the specified buffer size, window size and scheduler.
         *  @param {Number} [bufferSize] Maximum element count of the replay buffer.
         *  @param {Number} [windowSize] Maximum time length of the replay buffer.
         *  @param {Scheduler} [scheduler] Scheduler the observers are invoked on.
         */
        function ReplaySubject(bufferSize, windowSize, scheduler) {
            this.bufferSize = bufferSize == null ? maxSafeInteger : bufferSize;
            this.windowSize = windowSize == null ? maxSafeInteger : windowSize;
            this.scheduler = scheduler || currentThreadScheduler;
            this.q = [];
            this.observers = [];
            this.isStopped = false;
            this.isDisposed = false;
            this.hasError = false;
            this.error = null;
            __super__.call(this);
        }

        addProperties(ReplaySubject.prototype, Observer.prototype, {
            _subscribe: function (o) {
                checkDisposed(this);
                var so = new ScheduledObserver(this.scheduler, o), subscription = createRemovableDisposable(this, so);

                this._trim(this.scheduler.now());
                this.observers.push(so);

                for (var i = 0, len = this.q.length; i < len; i++) {
                    so.onNext(this.q[i].value);
                }

                if (this.hasError) {
                    so.onError(this.error);
                } else if (this.isStopped) {
                    so.onCompleted();
                }

                so.ensureActive();
                return subscription;
            },
            /**
             * Indicates whether the subject has observers subscribed to it.
             * @returns {Boolean} Indicates whether the subject has observers subscribed to it.
             */
            hasObservers: function () { checkDisposed(this); return this.observers.length > 0; },
            _trim: function (now) {
                while (this.q.length > this.bufferSize) {
                    this.q.shift();
                }
                while (this.q.length > 0 && (now - this.q[0].interval) > this.windowSize) {
                    this.q.shift();
                }
            },
            /**
             * Notifies all subscribed observers about the arrival of the specified element in the sequence.
             * @param {Mixed} value The value to send to all observers.
             */
            onNext: function (value) {
                checkDisposed(this);
                if (this.isStopped) { return; }
                var now = this.scheduler.now();
                this.q.push({ interval: now, value: value });
                this._trim(now);

                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    var observer = os[i];
                    observer.onNext(value);
                    observer.ensureActive();
                }
            },
            /**
             * Notifies all subscribed observers about the exception.
             * @param {Mixed} error The exception to send to all observers.
             */
            onError: function (error) {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.isStopped = true;
                this.error = error;
                this.hasError = true;
                var now = this.scheduler.now();
                this._trim(now);
                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    var observer = os[i];
                    observer.onError(error);
                    observer.ensureActive();
                }
                this.observers.length = 0;
            },
            /**
             * Notifies all subscribed observers about the end of the sequence.
             */
            onCompleted: function () {
                checkDisposed(this);
                if (this.isStopped) { return; }
                this.isStopped = true;
                var now = this.scheduler.now();
                this._trim(now);
                for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) {
                    var observer = os[i];
                    observer.onCompleted();
                    observer.ensureActive();
                }
                this.observers.length = 0;
            },
            /**
             * Unsubscribe all observers and release resources.
             */
            dispose: function () {
                this.isDisposed = true;
                this.observers = null;
            }
        });

        return ReplaySubject;
    }(Observable));

    /**
    * Used to pause and resume streams.
    */
    Rx.Pauser = (function (__super__) {
        inherits(Pauser, __super__);
        function Pauser() {
            __super__.call(this);
        }

        /**
         * Pauses the underlying sequence.
         */
        Pauser.prototype.pause = function () { this.onNext(false); };

        /**
        * Resumes the underlying sequence.
        */
        Pauser.prototype.resume = function () { this.onNext(true); };

        return Pauser;
    }(Subject));
    
    __LMtarget.Rx = Rx;

    // All code before this point will be filtered from stack traces.
    var rEndingLine = captureLine();

}.call(this, __LiteMolRxTemp, __LiteMolPromise));

var __LiteMolRx = __LiteMolRxTemp.Rx;
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    CIFTools.VERSION = { number: "1.1.6", date: "June 26 2017" };
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Utils;
    (function (Utils) {
        var ChunkedArray;
        (function (ChunkedArray) {
            function is(x) {
                return x.creator && x.chunkSize;
            }
            ChunkedArray.is = is;
            function add4(array, x, y, z, w) {
                if (array.currentIndex >= array.chunkSize) {
                    array.currentIndex = 0;
                    array.current = array.creator(array.chunkSize);
                    array.parts[array.parts.length] = array.current;
                }
                array.current[array.currentIndex++] = x;
                array.current[array.currentIndex++] = y;
                array.current[array.currentIndex++] = z;
                array.current[array.currentIndex++] = w;
                return array.elementCount++;
            }
            ChunkedArray.add4 = add4;
            function add3(array, x, y, z) {
                if (array.currentIndex >= array.chunkSize) {
                    array.currentIndex = 0;
                    array.current = array.creator(array.chunkSize);
                    array.parts[array.parts.length] = array.current;
                }
                array.current[array.currentIndex++] = x;
                array.current[array.currentIndex++] = y;
                array.current[array.currentIndex++] = z;
                return array.elementCount++;
            }
            ChunkedArray.add3 = add3;
            function add2(array, x, y) {
                if (array.currentIndex >= array.chunkSize) {
                    array.currentIndex = 0;
                    array.current = array.creator(array.chunkSize);
                    array.parts[array.parts.length] = array.current;
                }
                array.current[array.currentIndex++] = x;
                array.current[array.currentIndex++] = y;
                return array.elementCount++;
            }
            ChunkedArray.add2 = add2;
            function add(array, x) {
                if (array.currentIndex >= array.chunkSize) {
                    array.currentIndex = 0;
                    array.current = array.creator(array.chunkSize);
                    array.parts[array.parts.length] = array.current;
                }
                array.current[array.currentIndex++] = x;
                return array.elementCount++;
            }
            ChunkedArray.add = add;
            function compact(array) {
                var ret = array.creator(array.elementSize * array.elementCount), offset = (array.parts.length - 1) * array.chunkSize, offsetInner = 0, part;
                if (array.parts.length > 1) {
                    if (array.parts[0].buffer) {
                        for (var i = 0; i < array.parts.length - 1; i++) {
                            ret.set(array.parts[i], array.chunkSize * i);
                        }
                    }
                    else {
                        for (var i = 0; i < array.parts.length - 1; i++) {
                            offsetInner = array.chunkSize * i;
                            part = array.parts[i];
                            for (var j = 0; j < array.chunkSize; j++) {
                                ret[offsetInner + j] = part[j];
                            }
                        }
                    }
                }
                if (array.current.buffer && array.currentIndex >= array.chunkSize) {
                    ret.set(array.current, array.chunkSize * (array.parts.length - 1));
                }
                else {
                    for (var i = 0; i < array.currentIndex; i++) {
                        ret[offset + i] = array.current[i];
                    }
                }
                return ret;
            }
            ChunkedArray.compact = compact;
            function forVertex3D(chunkVertexCount) {
                if (chunkVertexCount === void 0) { chunkVertexCount = 262144; }
                return create(function (size) { return new Float32Array(size); }, chunkVertexCount, 3);
            }
            ChunkedArray.forVertex3D = forVertex3D;
            function forIndexBuffer(chunkIndexCount) {
                if (chunkIndexCount === void 0) { chunkIndexCount = 262144; }
                return create(function (size) { return new Uint32Array(size); }, chunkIndexCount, 3);
            }
            ChunkedArray.forIndexBuffer = forIndexBuffer;
            function forTokenIndices(chunkTokenCount) {
                if (chunkTokenCount === void 0) { chunkTokenCount = 131072; }
                return create(function (size) { return new Int32Array(size); }, chunkTokenCount, 2);
            }
            ChunkedArray.forTokenIndices = forTokenIndices;
            function forIndices(chunkTokenCount) {
                if (chunkTokenCount === void 0) { chunkTokenCount = 131072; }
                return create(function (size) { return new Int32Array(size); }, chunkTokenCount, 1);
            }
            ChunkedArray.forIndices = forIndices;
            function forInt32(chunkSize) {
                if (chunkSize === void 0) { chunkSize = 131072; }
                return create(function (size) { return new Int32Array(size); }, chunkSize, 1);
            }
            ChunkedArray.forInt32 = forInt32;
            function forFloat32(chunkSize) {
                if (chunkSize === void 0) { chunkSize = 131072; }
                return create(function (size) { return new Float32Array(size); }, chunkSize, 1);
            }
            ChunkedArray.forFloat32 = forFloat32;
            function forArray(chunkSize) {
                if (chunkSize === void 0) { chunkSize = 131072; }
                return create(function (size) { return []; }, chunkSize, 1);
            }
            ChunkedArray.forArray = forArray;
            function create(creator, chunkElementCount, elementSize) {
                chunkElementCount = chunkElementCount | 0;
                if (chunkElementCount <= 0)
                    chunkElementCount = 1;
                var chunkSize = chunkElementCount * elementSize;
                var current = creator(chunkSize);
                return {
                    elementSize: elementSize,
                    chunkSize: chunkSize,
                    creator: creator,
                    current: current,
                    parts: [current],
                    currentIndex: 0,
                    elementCount: 0
                };
            }
            ChunkedArray.create = create;
        })(ChunkedArray = Utils.ChunkedArray || (Utils.ChunkedArray = {}));
    })(Utils = CIFTools.Utils || (CIFTools.Utils = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
/**
 * Efficient integer and float parsers.
 *
 * For the purposes of parsing numbers from the mmCIF data representations,
 * up to 4 times faster than JS parseInt/parseFloat.
 */
var CIFTools;
(function (CIFTools) {
    var Utils;
    (function (Utils) {
        var FastNumberParsers;
        (function (FastNumberParsers) {
            "use strict";
            function parseIntSkipTrailingWhitespace(str, start, end) {
                while (start < end && str.charCodeAt(start) === 32)
                    start++;
                return parseInt(str, start, end);
            }
            FastNumberParsers.parseIntSkipTrailingWhitespace = parseIntSkipTrailingWhitespace;
            function parseInt(str, start, end) {
                var ret = 0, neg = 1;
                if (str.charCodeAt(start) === 45 /* - */) {
                    neg = -1;
                    start++;
                }
                for (; start < end; start++) {
                    var c = str.charCodeAt(start) - 48;
                    if (c > 9 || c < 0)
                        return (neg * ret) | 0;
                    else
                        ret = (10 * ret + c) | 0;
                }
                return neg * ret;
            }
            FastNumberParsers.parseInt = parseInt;
            function parseScientific(main, str, start, end) {
                // handle + in '1e+1' separately.
                if (str.charCodeAt(start) === 43 /* + */)
                    start++;
                return main * Math.pow(10.0, parseInt(str, start, end));
            }
            function parseFloatSkipTrailingWhitespace(str, start, end) {
                while (start < end && str.charCodeAt(start) === 32)
                    start++;
                return parseFloat(str, start, end);
            }
            FastNumberParsers.parseFloatSkipTrailingWhitespace = parseFloatSkipTrailingWhitespace;
            function parseFloat(str, start, end) {
                var neg = 1.0, ret = 0.0, point = 0.0, div = 1.0;
                if (str.charCodeAt(start) === 45) {
                    neg = -1.0;
                    ++start;
                }
                while (start < end) {
                    var c = str.charCodeAt(start) - 48;
                    if (c >= 0 && c < 10) {
                        ret = ret * 10 + c;
                        ++start;
                    }
                    else if (c === -2) {
                        ++start;
                        while (start < end) {
                            c = str.charCodeAt(start) - 48;
                            if (c >= 0 && c < 10) {
                                point = 10.0 * point + c;
                                div = 10.0 * div;
                                ++start;
                            }
                            else if (c === 53 || c === 21) {
                                return parseScientific(neg * (ret + point / div), str, start + 1, end);
                            }
                            else {
                                return neg * (ret + point / div);
                            }
                        }
                        return neg * (ret + point / div);
                    }
                    else if (c === 53 || c === 21) {
                        return parseScientific(neg * ret, str, start + 1, end);
                    }
                    else
                        break;
                }
                return neg * ret;
            }
            FastNumberParsers.parseFloat = parseFloat;
        })(FastNumberParsers = Utils.FastNumberParsers || (Utils.FastNumberParsers = {}));
    })(Utils = CIFTools.Utils || (CIFTools.Utils = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Utils;
    (function (Utils) {
        var __paddingSpaces = [];
        (function () {
            var s = '';
            for (var i = 0; i < 512; i++) {
                __paddingSpaces[i] = s;
                s = s + ' ';
            }
        })();
        var StringWriter;
        (function (StringWriter) {
            function create(chunkCapacity) {
                if (chunkCapacity === void 0) { chunkCapacity = 512; }
                return {
                    chunkData: [],
                    chunkOffset: 0,
                    chunkCapacity: chunkCapacity,
                    data: []
                };
            }
            StringWriter.create = create;
            function asString(writer) {
                if (!writer.data.length) {
                    if (writer.chunkData.length === writer.chunkOffset)
                        return writer.chunkData.join('');
                    return writer.chunkData.splice(0, writer.chunkOffset).join('');
                }
                if (writer.chunkOffset > 0) {
                    writer.data[writer.data.length] = writer.chunkData.splice(0, writer.chunkOffset).join('');
                }
                return writer.data.join('');
            }
            StringWriter.asString = asString;
            function writeTo(writer, stream) {
                finalize(writer);
                for (var _i = 0, _a = writer.data; _i < _a.length; _i++) {
                    var s = _a[_i];
                    stream.writeString(s);
                }
            }
            StringWriter.writeTo = writeTo;
            function finalize(writer) {
                if (writer.chunkOffset > 0) {
                    if (writer.chunkData.length === writer.chunkOffset)
                        writer.data[writer.data.length] = writer.chunkData.join('');
                    else
                        writer.data[writer.data.length] = writer.chunkData.splice(0, writer.chunkOffset).join('');
                    writer.chunkOffset = 0;
                }
            }
            function newline(writer) {
                write(writer, '\n');
            }
            StringWriter.newline = newline;
            function whitespace(writer, len) {
                write(writer, __paddingSpaces[len]);
            }
            StringWriter.whitespace = whitespace;
            function write(writer, val) {
                if (val === undefined || val === null) {
                    return;
                }
                if (writer.chunkOffset === writer.chunkCapacity) {
                    writer.data[writer.data.length] = writer.chunkData.join('');
                    writer.chunkOffset = 0;
                }
                writer.chunkData[writer.chunkOffset++] = val;
            }
            StringWriter.write = write;
            function writeSafe(writer, val) {
                if (writer.chunkOffset === writer.chunkCapacity) {
                    writer.data[writer.data.length] = writer.chunkData.join('');
                    writer.chunkOffset = 0;
                }
                writer.chunkData[writer.chunkOffset++] = val;
            }
            StringWriter.writeSafe = writeSafe;
            function writePadLeft(writer, val, totalWidth) {
                if (val === undefined || val === null) {
                    write(writer, __paddingSpaces[totalWidth]);
                }
                var padding = totalWidth - val.length;
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
                write(writer, val);
            }
            StringWriter.writePadLeft = writePadLeft;
            function writePadRight(writer, val, totalWidth) {
                if (val === undefined || val === null) {
                    write(writer, __paddingSpaces[totalWidth]);
                }
                var padding = totalWidth - val.length;
                write(writer, val);
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
            }
            StringWriter.writePadRight = writePadRight;
            function writeInteger(writer, val) {
                write(writer, '' + val);
            }
            StringWriter.writeInteger = writeInteger;
            function writeIntegerPadLeft(writer, val, totalWidth) {
                var s = '' + val;
                var padding = totalWidth - s.length;
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
                write(writer, s);
            }
            StringWriter.writeIntegerPadLeft = writeIntegerPadLeft;
            function writeIntegerPadRight(writer, val, totalWidth) {
                var s = '' + val;
                var padding = totalWidth - s.length;
                write(writer, s);
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
            }
            StringWriter.writeIntegerPadRight = writeIntegerPadRight;
            /**
             * @example writeFloat(123.2123, 100) -- 2 decim
             */
            function writeFloat(writer, val, precisionMultiplier) {
                write(writer, '' + Math.round(precisionMultiplier * val) / precisionMultiplier);
            }
            StringWriter.writeFloat = writeFloat;
            function writeFloatPadLeft(writer, val, precisionMultiplier, totalWidth) {
                var s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;
                var padding = totalWidth - s.length;
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
                write(writer, s);
            }
            StringWriter.writeFloatPadLeft = writeFloatPadLeft;
            function writeFloatPadRight(writer, val, precisionMultiplier, totalWidth) {
                var s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;
                var padding = totalWidth - s.length;
                write(writer, s);
                if (padding > 0)
                    write(writer, __paddingSpaces[padding]);
            }
            StringWriter.writeFloatPadRight = writeFloatPadRight;
        })(StringWriter = Utils.StringWriter || (Utils.StringWriter = {}));
    })(Utils = CIFTools.Utils || (CIFTools.Utils = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    "use strict";
    /**
     * Represents a column that is not present.
     */
    var _UndefinedColumn = (function () {
        function _UndefinedColumn() {
            this.isDefined = false;
        }
        _UndefinedColumn.prototype.getString = function (row) { return null; };
        ;
        _UndefinedColumn.prototype.getInteger = function (row) { return 0; };
        _UndefinedColumn.prototype.getFloat = function (row) { return 0.0; };
        _UndefinedColumn.prototype.getValuePresence = function (row) { return 1 /* NotSpecified */; };
        _UndefinedColumn.prototype.areValuesEqual = function (rowA, rowB) { return true; };
        _UndefinedColumn.prototype.stringEquals = function (row, value) { return value === null; };
        return _UndefinedColumn;
    }());
    CIFTools.UndefinedColumn = new _UndefinedColumn();
    /**
     * Helper functions for categoies.
     */
    var Category;
    (function (Category) {
        /**
         * Extracts a matrix from a category from a specified rowIndex.
         *
         * _category.matrix[1][1] v11
         * ....
         * ....
         * _category.matrix[rows][cols] vRowsCols
         */
        function getMatrix(category, field, rows, cols, rowIndex) {
            var ret = [];
            for (var i = 1; i <= rows; i++) {
                var row = [];
                for (var j = 1; j <= cols; j++) {
                    row[j - 1] = category.getColumn(field + "[" + i + "][" + j + "]").getFloat(rowIndex);
                }
                ret[i - 1] = row;
            }
            return ret;
        }
        Category.getMatrix = getMatrix;
        /**
         * Extracts a vector from a category from a specified rowIndex.
         *
         * _category.matrix[1][1] v11
         * ....
         * ....
         * _category.matrix[rows][cols] vRowsCols
         */
        function getVector(category, field, rows, cols, rowIndex) {
            var ret = [];
            for (var i = 1; i <= rows; i++) {
                ret[i - 1] = category.getColumn(field + "[" + i + "]").getFloat(rowIndex);
            }
            return ret;
        }
        Category.getVector = getVector;
    })(Category = CIFTools.Category || (CIFTools.Category = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    "use strict";
    var ParserResult;
    (function (ParserResult) {
        function error(message, line) {
            if (line === void 0) { line = -1; }
            return new ParserError(message, line);
        }
        ParserResult.error = error;
        function success(result, warnings) {
            if (warnings === void 0) { warnings = []; }
            return new ParserSuccess(result, warnings);
        }
        ParserResult.success = success;
    })(ParserResult = CIFTools.ParserResult || (CIFTools.ParserResult = {}));
    var ParserError = (function () {
        function ParserError(message, line) {
            this.message = message;
            this.line = line;
            this.isError = true;
        }
        ParserError.prototype.toString = function () {
            if (this.line >= 0) {
                return "[Line " + this.line + "] " + this.message;
            }
            return this.message;
        };
        return ParserError;
    }());
    CIFTools.ParserError = ParserError;
    var ParserSuccess = (function () {
        function ParserSuccess(result, warnings) {
            this.result = result;
            this.warnings = warnings;
            this.isError = false;
        }
        return ParserSuccess;
    }());
    CIFTools.ParserSuccess = ParserSuccess;
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
/*
    On data representation of molecular files

    Consider an mmCIF file that stores a molecule with 100k atoms. For the sake of simplicity,
    lets ignore things like symmetry or assemblies, and assume, that the file only stores the
    _atom_site records. The atom site "table" in the standard mmCIF from PDB database currently
    has 26 columns.

    So the data looks something like this:

        loop_
        _atom_site.column1
        ....
        _atom_site.column26
        t1,1 .... t1,26
        t100000,1 .... t100000,26

    The straightforward way to represent this data in JavaScript is to have an array of objects
    with properties named "column1" ..., "column26":

        [{ column1: "t1,1", ..., column26: "t1,26" },
          ...,
         { column1: "t100000,1", ..., column26: "t100000,26" }]

    So in order to represent the atoms sites, we would need 100k objects and 2.6 million strings.
    Is this bad? well, sort of. It would not be so bad if this representation would be the only
    thing we need to keep in memory and/or the life time of the object was short. But usually
    we would need to keep the object around for the entire lifetime of the app. This alone
    adds a very non-significant overhead for the garbage collector (which increases the app's
    latency). What's worse is that we usually only need a fraction of this data, but this can
    vary application for application. For just 100k atoms, the overhead is not "that bad", but
    consider 1M atoms and suddenly we have a problem.

    The following data model shows an alternative way of storing molecular file s
    in memory that is very efficient, fast and introduces a very minimal overhead.

 */
var CIFTools;
(function (CIFTools) {
    var Text;
    (function (Text) {
        "use strict";
        var ShortStringPool;
        (function (ShortStringPool) {
            function create() { return Object.create(null); }
            ShortStringPool.create = create;
            function get(pool, str) {
                if (str.length > 6)
                    return str;
                var value = pool[str];
                if (value !== void 0)
                    return value;
                pool[str] = str;
                return str;
            }
            ShortStringPool.get = get;
        })(ShortStringPool || (ShortStringPool = {}));
        /**
         * Represents the input file.
         */
        var File = (function () {
            function File(data) {
                /**
                 * Data blocks inside the file. If no data block is present, a "default" one is created.
                 */
                this.dataBlocks = [];
                this.data = data;
            }
            File.prototype.toJSON = function () {
                return this.dataBlocks.map(function (b) { return b.toJSON(); });
            };
            return File;
        }());
        Text.File = File;
        /**
         * Represents a single data block.
         */
        var DataBlock = (function () {
            function DataBlock(data, header) {
                this.header = header;
                this.data = data;
                this.categoryList = [];
                this.additionalData = {};
                this.categoryMap = new Map();
            }
            Object.defineProperty(DataBlock.prototype, "categories", {
                /**
                 * Categories of the block.
                 * block.categories._atom_site / ['_atom_site']
                 */
                get: function () {
                    return this.categoryList;
                },
                enumerable: true,
                configurable: true
            });
            /**
             * Gets a category by its name.
             */
            DataBlock.prototype.getCategory = function (name) {
                return this.categoryMap.get(name);
            };
            /**
             * Adds a category.
             */
            DataBlock.prototype.addCategory = function (category) {
                this.categoryList[this.categoryList.length] = category;
                this.categoryMap.set(category.name, category);
            };
            DataBlock.prototype.toJSON = function () {
                return {
                    id: this.header,
                    categories: this.categoryList.map(function (c) { return c.toJSON(); }),
                    additionalData: this.additionalData
                };
            };
            return DataBlock;
        }());
        Text.DataBlock = DataBlock;
        /**
         * Represents a single CIF category.
         */
        var Category = (function () {
            function Category(data, name, startIndex, endIndex, columns, tokens, tokenCount) {
                this.name = name;
                this.tokens = tokens;
                this.data = data;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.columnCount = columns.length;
                this.rowCount = (tokenCount / columns.length) | 0;
                this.columnIndices = new Map();
                this.columnNameList = [];
                for (var i = 0; i < columns.length; i++) {
                    var colName = columns[i].substr(name.length + 1);
                    this.columnIndices.set(colName, i);
                    this.columnNameList.push(colName);
                }
            }
            Object.defineProperty(Category.prototype, "columnNames", {
                /**
                 * The array of columns.
                 */
                get: function () {
                    return this.columnNameList;
                },
                enumerable: true,
                configurable: true
            });
            /**
             * Get a column object that makes accessing data easier.
             * @returns undefined if the column isn't present, the Column object otherwise.
             */
            Category.prototype.getColumn = function (name) {
                var i = this.columnIndices.get(name);
                if (i !== void 0)
                    return new Column(this, this.data, name, i);
                return CIFTools.UndefinedColumn;
            };
            Category.prototype.toJSON = function () {
                var rows = [], data = this.data, tokens = this.tokens;
                var colNames = this.columnNameList;
                var strings = ShortStringPool.create();
                for (var i = 0; i < this.rowCount; i++) {
                    var item = {};
                    for (var j = 0; j < this.columnCount; j++) {
                        var tk = (i * this.columnCount + j) * 2;
                        item[colNames[j]] = ShortStringPool.get(strings, data.substring(tokens[tk], tokens[tk + 1]));
                    }
                    rows[i] = item;
                }
                return { name: this.name, columns: colNames, rows: rows };
            };
            return Category;
        }());
        Text.Category = Category;
        var fastParseInt = CIFTools.Utils.FastNumberParsers.parseInt;
        var fastParseFloat = CIFTools.Utils.FastNumberParsers.parseFloat;
        /**
         * Represents a single column of a CIF category.
         */
        var Column = (function () {
            function Column(category, data, name, index) {
                this.data = data;
                this.name = name;
                this.index = index;
                this.stringPool = ShortStringPool.create();
                this.isDefined = true;
                this.tokens = category.tokens;
                this.columnCount = category.columnCount;
            }
            /**
             * Returns the string value at given row.
             */
            Column.prototype.getString = function (row) {
                var i = (row * this.columnCount + this.index) * 2;
                var ret = ShortStringPool.get(this.stringPool, this.data.substring(this.tokens[i], this.tokens[i + 1]));
                if (ret === "." || ret === "?")
                    return null;
                return ret;
            };
            /**
             * Returns the integer value at given row.
             */
            Column.prototype.getInteger = function (row) {
                var i = (row * this.columnCount + this.index) * 2;
                return fastParseInt(this.data, this.tokens[i], this.tokens[i + 1]);
            };
            /**
             * Returns the float value at given row.
             */
            Column.prototype.getFloat = function (row) {
                var i = (row * this.columnCount + this.index) * 2;
                return fastParseFloat(this.data, this.tokens[i], this.tokens[i + 1]);
            };
            /**
             * Returns true if the token has the specified string value.
             */
            Column.prototype.stringEquals = function (row, value) {
                var aIndex = (row * this.columnCount + this.index) * 2, s = this.tokens[aIndex], len = value.length;
                if (len !== this.tokens[aIndex + 1] - s)
                    return false;
                for (var i = 0; i < len; i++) {
                    if (this.data.charCodeAt(i + s) !== value.charCodeAt(i))
                        return false;
                }
                return true;
            };
            /**
             * Determines if values at the given rows are equal.
             */
            Column.prototype.areValuesEqual = function (rowA, rowB) {
                var aIndex = (rowA * this.columnCount + this.index) * 2, bIndex = (rowB * this.columnCount + this.index) * 2;
                var aS = this.tokens[aIndex], bS = this.tokens[bIndex], len = this.tokens[aIndex + 1] - aS;
                if (len !== this.tokens[bIndex + 1] - bS)
                    return false;
                for (var i = 0; i < len; i++) {
                    if (this.data.charCodeAt(i + aS) !== this.data.charCodeAt(i + bS)) {
                        return false;
                    }
                }
                return true;
            };
            /**
             * Returns true if the value is not defined (. or ? token).
             */
            Column.prototype.getValuePresence = function (row) {
                var index = row * this.columnCount + this.index;
                var s = this.tokens[2 * index];
                if (this.tokens[2 * index + 1] - s !== 1)
                    return 0 /* Present */;
                var v = this.data.charCodeAt(s);
                if (v === 46 /* . */)
                    return 1 /* NotSpecified */;
                if (v === 63 /* ? */)
                    return 2 /* Unknown */;
                return 0 /* Present */;
            };
            return Column;
        }());
        Text.Column = Column;
    })(Text = CIFTools.Text || (CIFTools.Text = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Text;
    (function (Text) {
        "use strict";
        var TokenIndexBuilder;
        (function (TokenIndexBuilder) {
            function resize(builder) {
                // scale the size using golden ratio, because why not.
                var newBuffer = new Int32Array((1.61 * builder.tokens.length) | 0);
                newBuffer.set(builder.tokens);
                builder.tokens = newBuffer;
                builder.tokensLenMinus2 = (newBuffer.length - 2) | 0;
            }
            function addToken(builder, start, end) {
                if (builder.count >= builder.tokensLenMinus2) {
                    resize(builder);
                }
                builder.tokens[builder.count++] = start;
                builder.tokens[builder.count++] = end;
            }
            TokenIndexBuilder.addToken = addToken;
            function create(size) {
                return {
                    tokensLenMinus2: (size - 2) | 0,
                    count: 0,
                    tokens: new Int32Array(size)
                };
            }
            TokenIndexBuilder.create = create;
        })(TokenIndexBuilder || (TokenIndexBuilder = {}));
        /**
         * Eat everything until a whitespace/newline occurs.
         */
        function eatValue(state) {
            while (state.position < state.length) {
                switch (state.data.charCodeAt(state.position)) {
                    case 9: // \t
                    case 10: // \n
                    case 13: // \r
                    case 32:
                        state.currentTokenEnd = state.position;
                        return;
                    default:
                        ++state.position;
                        break;
                }
            }
            state.currentTokenEnd = state.position;
        }
        /**
         * Eats an escaped values. Handles the "degenerate" cases as well.
         *
         * "Degenerate" cases:
         * - 'xx'x' => xx'x
         * - 'xxxNEWLINE => 'xxx
         *
         */
        function eatEscaped(state, esc) {
            var next, c;
            ++state.position;
            while (state.position < state.length) {
                c = state.data.charCodeAt(state.position);
                if (c === esc) {
                    next = state.data.charCodeAt(state.position + 1);
                    switch (next) {
                        case 9: // \t
                        case 10: // \n
                        case 13: // \r
                        case 32:
                            // get rid of the quotes.
                            state.currentTokenStart++;
                            state.currentTokenEnd = state.position;
                            state.isEscaped = true;
                            ++state.position;
                            return;
                        default:
                            if (next === void 0) {
                                // get rid of the quotes.
                                state.currentTokenStart++;
                                state.currentTokenEnd = state.position;
                                state.isEscaped = true;
                                ++state.position;
                                return;
                            }
                            ++state.position;
                            break;
                    }
                }
                else {
                    // handle 'xxxNEWLINE => 'xxx
                    if (c === 10 || c === 13) {
                        state.currentTokenEnd = state.position;
                        return;
                    }
                    ++state.position;
                }
            }
            state.currentTokenEnd = state.position;
        }
        /**
         * Eats a multiline token of the form NL;....NL;
         */
        function eatMultiline(state) {
            var prev = 59, pos = state.position + 1, c;
            while (pos < state.length) {
                c = state.data.charCodeAt(pos);
                if (c === 59 && (prev === 10 || prev === 13)) {
                    state.position = pos + 1;
                    // get rid of the ;
                    state.currentTokenStart++;
                    // remove trailing newlines
                    pos--;
                    c = state.data.charCodeAt(pos);
                    while (c === 10 || c === 13) {
                        pos--;
                        c = state.data.charCodeAt(pos);
                    }
                    state.currentTokenEnd = pos + 1;
                    state.isEscaped = true;
                    return;
                }
                else {
                    // handle line numbers
                    if (c === 13) {
                        state.currentLineNumber++;
                    }
                    else if (c === 10 && prev !== 13) {
                        state.currentLineNumber++;
                    }
                    prev = c;
                    ++pos;
                }
            }
            state.position = pos;
            return prev;
        }
        /**
         * Skips until \n or \r occurs -- therefore the newlines get handled by the "skipWhitespace" function.
         */
        function skipCommentLine(state) {
            while (state.position < state.length) {
                var c = state.data.charCodeAt(state.position);
                if (c === 10 || c === 13) {
                    return;
                }
                ++state.position;
            }
        }
        /**
         * Skips all the whitespace - space, tab, newline, CR
         * Handles incrementing line count.
         */
        function skipWhitespace(state) {
            var prev = 10;
            while (state.position < state.length) {
                var c = state.data.charCodeAt(state.position);
                switch (c) {
                    case 9: // '\t'
                    case 32:
                        prev = c;
                        ++state.position;
                        break;
                    case 10:
                        // handle \r\n
                        if (prev !== 13) {
                            ++state.currentLineNumber;
                        }
                        prev = c;
                        ++state.position;
                        break;
                    case 13:
                        prev = c;
                        ++state.position;
                        ++state.currentLineNumber;
                        break;
                    default:
                        return prev;
                }
            }
            return prev;
        }
        function isData(state) {
            // here we already assume the 5th char is _ and that the length >= 5
            // d/D
            var c = state.data.charCodeAt(state.currentTokenStart);
            if (c !== 68 && c !== 100)
                return false;
            // a/A
            c = state.data.charCodeAt(state.currentTokenStart + 1);
            if (c !== 65 && c !== 97)
                return false;
            // t/t
            c = state.data.charCodeAt(state.currentTokenStart + 2);
            if (c !== 84 && c !== 116)
                return false;
            // a/A
            c = state.data.charCodeAt(state.currentTokenStart + 3);
            if (c !== 65 && c !== 97)
                return false;
            return true;
        }
        function isSave(state) {
            // here we already assume the 5th char is _ and that the length >= 5
            // s/S
            var c = state.data.charCodeAt(state.currentTokenStart);
            if (c !== 83 && c !== 115)
                return false;
            // a/A
            c = state.data.charCodeAt(state.currentTokenStart + 1);
            if (c !== 65 && c !== 97)
                return false;
            // v/V
            c = state.data.charCodeAt(state.currentTokenStart + 2);
            if (c !== 86 && c !== 118)
                return false;
            // e/E
            c = state.data.charCodeAt(state.currentTokenStart + 3);
            if (c !== 69 && c !== 101)
                return false;
            return true;
        }
        function isLoop(state) {
            // here we already assume the 5th char is _ and that the length >= 5
            if (state.currentTokenEnd - state.currentTokenStart !== 5)
                return false;
            // l/L
            var c = state.data.charCodeAt(state.currentTokenStart);
            if (c !== 76 && c !== 108)
                return false;
            // o/O
            c = state.data.charCodeAt(state.currentTokenStart + 1);
            if (c !== 79 && c !== 111)
                return false;
            // o/O
            c = state.data.charCodeAt(state.currentTokenStart + 2);
            if (c !== 79 && c !== 111)
                return false;
            // p/P
            c = state.data.charCodeAt(state.currentTokenStart + 3);
            if (c !== 80 && c !== 112)
                return false;
            return true;
        }
        /**
         * Checks if the current token shares the namespace with string at <start,end).
         */
        function isNamespace(state, start, end) {
            var i, nsLen = end - start, offset = state.currentTokenStart - start, tokenLen = state.currentTokenEnd - state.currentTokenStart;
            if (tokenLen < nsLen)
                return false;
            for (i = start; i < end; ++i) {
                if (state.data.charCodeAt(i) !== state.data.charCodeAt(i + offset))
                    return false;
            }
            if (nsLen === tokenLen)
                return true;
            if (state.data.charCodeAt(i + offset) === 46) {
                return true;
            }
            return false;
        }
        /**
         * Returns the index of '.' in the current token. If no '.' is present, returns currentTokenEnd.
         */
        function getNamespaceEnd(state) {
            var i;
            for (i = state.currentTokenStart; i < state.currentTokenEnd; ++i) {
                if (state.data.charCodeAt(i) === 46)
                    return i;
            }
            return i;
        }
        /**
         * Get the namespace string. endIndex is obtained by the getNamespaceEnd() function.
         */
        function getNamespace(state, endIndex) {
            return state.data.substring(state.currentTokenStart, endIndex);
        }
        /**
         * String representation of the current token.
         */
        function getTokenString(state) {
            return state.data.substring(state.currentTokenStart, state.currentTokenEnd);
        }
        /**
         * Move to the next token.
         */
        function moveNextInternal(state) {
            var prev = skipWhitespace(state);
            if (state.position >= state.length) {
                state.currentTokenType = 6 /* End */;
                return;
            }
            state.currentTokenStart = state.position;
            state.currentTokenEnd = state.position;
            state.isEscaped = false;
            var c = state.data.charCodeAt(state.position);
            switch (c) {
                case 35:
                    skipCommentLine(state);
                    state.currentTokenType = 5 /* Comment */;
                    break;
                case 34: // ", escaped value
                case 39:
                    eatEscaped(state, c);
                    state.currentTokenType = 3 /* Value */;
                    break;
                case 59:
                    // multiline value must start at the beginning of the line.
                    if (prev === 10 || prev === 13) {
                        eatMultiline(state);
                    }
                    else {
                        eatValue(state);
                    }
                    state.currentTokenType = 3 /* Value */;
                    break;
                default:
                    eatValue(state);
                    // escaped is always Value
                    if (state.isEscaped) {
                        state.currentTokenType = 3 /* Value */;
                        // _ always means column name
                    }
                    else if (state.data.charCodeAt(state.currentTokenStart) === 95) {
                        state.currentTokenType = 4 /* ColumnName */;
                        // 5th char needs to be _ for data_ or loop_
                    }
                    else if (state.currentTokenEnd - state.currentTokenStart >= 5 && state.data.charCodeAt(state.currentTokenStart + 4) === 95) {
                        if (isData(state))
                            state.currentTokenType = 0 /* Data */;
                        else if (isSave(state))
                            state.currentTokenType = 1 /* Save */;
                        else if (isLoop(state))
                            state.currentTokenType = 2 /* Loop */;
                        else
                            state.currentTokenType = 3 /* Value */;
                        // all other tests failed, we are at Value token.
                    }
                    else {
                        state.currentTokenType = 3 /* Value */;
                    }
                    break;
            }
        }
        /**
         * Moves to the next non-comment token.
         */
        function moveNext(state) {
            moveNextInternal(state);
            while (state.currentTokenType === 5 /* Comment */)
                moveNextInternal(state);
        }
        function createTokenizer(data) {
            return {
                data: data,
                length: data.length,
                position: 0,
                currentTokenStart: 0,
                currentTokenEnd: 0,
                currentTokenType: 6 /* End */,
                currentLineNumber: 1,
                isEscaped: false
            };
        }
        /**
         * Reads a category containing a single row.
         */
        function handleSingle(tokenizer, block) {
            var nsStart = tokenizer.currentTokenStart, nsEnd = getNamespaceEnd(tokenizer), name = getNamespace(tokenizer, nsEnd), column, columns = [], tokens = TokenIndexBuilder.create(512), tokenCount = 0, readingNames = true;
            while (readingNames) {
                if (tokenizer.currentTokenType !== 4 /* ColumnName */ || !isNamespace(tokenizer, nsStart, nsEnd)) {
                    readingNames = false;
                    break;
                }
                column = getTokenString(tokenizer);
                moveNext(tokenizer);
                if (tokenizer.currentTokenType !== 3 /* Value */) {
                    return {
                        hasError: true,
                        errorLine: tokenizer.currentLineNumber,
                        errorMessage: "Expected value."
                    };
                }
                columns[columns.length] = column;
                TokenIndexBuilder.addToken(tokens, tokenizer.currentTokenStart, tokenizer.currentTokenEnd);
                tokenCount++;
                moveNext(tokenizer);
            }
            block.addCategory(new Text.Category(block.data, name, nsStart, tokenizer.currentTokenStart, columns, tokens.tokens, tokenCount));
            return {
                hasError: false,
                errorLine: 0,
                errorMessage: ""
            };
        }
        /**
         * Reads a loop.
         */
        function handleLoop(tokenizer, block) {
            var start = tokenizer.currentTokenStart, loopLine = tokenizer.currentLineNumber;
            moveNext(tokenizer);
            var name = getNamespace(tokenizer, getNamespaceEnd(tokenizer)), columns = [], tokens = TokenIndexBuilder.create(name === "_atom_site" ? (block.data.length / 1.85) | 0 : 1024), tokenCount = 0;
            while (tokenizer.currentTokenType === 4 /* ColumnName */) {
                columns[columns.length] = getTokenString(tokenizer);
                moveNext(tokenizer);
            }
            while (tokenizer.currentTokenType === 3 /* Value */) {
                TokenIndexBuilder.addToken(tokens, tokenizer.currentTokenStart, tokenizer.currentTokenEnd);
                tokenCount++;
                moveNext(tokenizer);
            }
            if (tokenCount % columns.length !== 0) {
                return {
                    hasError: true,
                    errorLine: tokenizer.currentLineNumber,
                    errorMessage: "The number of values for loop starting at line " + loopLine + " is not a multiple of the number of columns."
                };
            }
            block.addCategory(new Text.Category(block.data, name, start, tokenizer.currentTokenStart, columns, tokens.tokens, tokenCount));
            return {
                hasError: false,
                errorLine: 0,
                errorMessage: ""
            };
        }
        /**
         * Creates an error result.
         */
        function error(line, message) {
            return CIFTools.ParserResult.error(message, line);
        }
        /**
         * Creates a data result.
         */
        function result(data) {
            return CIFTools.ParserResult.success(data);
        }
        /**
         * Parses an mmCIF file.
         *
         * @returns CifParserResult wrapper of the result.
         */
        function parseInternal(data) {
            var tokenizer = createTokenizer(data), cat, id, file = new Text.File(data), block = new Text.DataBlock(data, "default"), saveFrame = new Text.DataBlock(data, "empty"), inSaveFrame = false, blockSaveFrames;
            moveNext(tokenizer);
            while (tokenizer.currentTokenType !== 6 /* End */) {
                var token = tokenizer.currentTokenType;
                // Data block
                if (token === 0 /* Data */) {
                    if (inSaveFrame) {
                        return error(tokenizer.currentLineNumber, "Unexpected data block inside a save frame.");
                    }
                    if (block.categories.length > 0) {
                        file.dataBlocks.push(block);
                    }
                    block = new Text.DataBlock(data, data.substring(tokenizer.currentTokenStart + 5, tokenizer.currentTokenEnd));
                    moveNext(tokenizer);
                    // Save frame
                }
                else if (token === 1 /* Save */) {
                    id = data.substring(tokenizer.currentTokenStart + 5, tokenizer.currentTokenEnd);
                    if (id.length === 0) {
                        if (saveFrame.categories.length > 0) {
                            blockSaveFrames = block.additionalData["saveFrames"];
                            if (!blockSaveFrames) {
                                blockSaveFrames = [];
                                block.additionalData["saveFrames"] = blockSaveFrames;
                            }
                            blockSaveFrames[blockSaveFrames.length] = saveFrame;
                        }
                        inSaveFrame = false;
                    }
                    else {
                        if (inSaveFrame) {
                            return error(tokenizer.currentLineNumber, "Save frames cannot be nested.");
                        }
                        inSaveFrame = true;
                        saveFrame = new Text.DataBlock(data, id);
                    }
                    moveNext(tokenizer);
                    // Loop
                }
                else if (token === 2 /* Loop */) {
                    cat = handleLoop(tokenizer, inSaveFrame ? saveFrame : block);
                    if (cat.hasError) {
                        return error(cat.errorLine, cat.errorMessage);
                    }
                    // Single row
                }
                else if (token === 4 /* ColumnName */) {
                    cat = handleSingle(tokenizer, inSaveFrame ? saveFrame : block);
                    if (cat.hasError) {
                        return error(cat.errorLine, cat.errorMessage);
                    }
                    // Out of options
                }
                else {
                    return error(tokenizer.currentLineNumber, "Unexpected token. Expected data_, loop_, or data name.");
                }
            }
            // Check if the latest save frame was closed.
            if (inSaveFrame) {
                return error(tokenizer.currentLineNumber, "Unfinished save frame (`" + saveFrame.header + "`).");
            }
            if (block.categories.length > 0) {
                file.dataBlocks.push(block);
            }
            return result(file);
        }
        function parse(data) {
            return parseInternal(data);
        }
        Text.parse = parse;
    })(Text = CIFTools.Text || (CIFTools.Text = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Text;
    (function (Text) {
        "use strict";
        var StringWriter = CIFTools.Utils.StringWriter;
        var Writer = (function () {
            function Writer() {
                this.writer = StringWriter.create();
                this.encoded = false;
                this.dataBlockCreated = false;
            }
            Writer.prototype.startDataBlock = function (header) {
                this.dataBlockCreated = true;
                StringWriter.write(this.writer, "data_" + (header || '').replace(/[ \n\t]/g, '').toUpperCase() + "\n#\n");
            };
            Writer.prototype.writeCategory = function (category, contexts) {
                if (this.encoded) {
                    throw new Error('The writer contents have already been encoded, no more writing.');
                }
                if (!this.dataBlockCreated) {
                    throw new Error('No data block created.');
                }
                var src = !contexts || !contexts.length ? [category(void 0)] : contexts.map(function (c) { return category(c); });
                var data = src.filter(function (c) { return c && c.count > 0; });
                if (!data.length)
                    return;
                var count = data.reduce(function (a, c) { return a + (c.count === void 0 ? 1 : c.count); }, 0);
                if (!count)
                    return;
                else if (count === 1) {
                    writeCifSingleRecord(data[0], this.writer);
                }
                else {
                    writeCifLoop(data, this.writer);
                }
            };
            Writer.prototype.encode = function () {
                this.encoded = true;
            };
            Writer.prototype.flush = function (stream) {
                StringWriter.writeTo(this.writer, stream);
            };
            return Writer;
        }());
        Text.Writer = Writer;
        function isMultiline(value) {
            return !!value && value.indexOf('\n') >= 0;
        }
        function writeCifSingleRecord(category, writer) {
            var fields = category.desc.fields;
            var data = category.data;
            var width = fields.reduce(function (w, s) { return Math.max(w, s.name.length); }, 0) + category.desc.name.length + 5;
            for (var _i = 0, fields_1 = fields; _i < fields_1.length; _i++) {
                var f = fields_1[_i];
                StringWriter.writePadRight(writer, category.desc.name + "." + f.name, width);
                var presence = f.presence;
                var p = presence ? presence(data, 0) : 0 /* Present */;
                if (p !== 0 /* Present */) {
                    if (p === 1 /* NotSpecified */)
                        writeNotSpecified(writer);
                    else
                        writeUnknown(writer);
                }
                else {
                    var val = f.string(data, 0);
                    if (isMultiline(val)) {
                        writeMultiline(writer, val);
                        StringWriter.newline(writer);
                    }
                    else {
                        writeChecked(writer, val);
                    }
                }
                StringWriter.newline(writer);
            }
            StringWriter.write(writer, '#\n');
        }
        function writeCifLoop(categories, writer) {
            writeLine(writer, 'loop_');
            var first = categories[0];
            var fields = first.desc.fields;
            for (var _i = 0, fields_2 = fields; _i < fields_2.length; _i++) {
                var f = fields_2[_i];
                writeLine(writer, first.desc.name + "." + f.name);
            }
            for (var _a = 0, categories_1 = categories; _a < categories_1.length; _a++) {
                var category = categories_1[_a];
                var data = category.data;
                var count = category.count;
                for (var i = 0; i < count; i++) {
                    for (var _b = 0, fields_3 = fields; _b < fields_3.length; _b++) {
                        var f = fields_3[_b];
                        var presence = f.presence;
                        var p = presence ? presence(data, i) : 0 /* Present */;
                        if (p !== 0 /* Present */) {
                            if (p === 1 /* NotSpecified */)
                                writeNotSpecified(writer);
                            else
                                writeUnknown(writer);
                        }
                        else {
                            var val = f.string(data, i);
                            if (isMultiline(val)) {
                                writeMultiline(writer, val);
                                StringWriter.newline(writer);
                            }
                            else {
                                writeChecked(writer, val);
                            }
                        }
                    }
                    StringWriter.newline(writer);
                }
            }
            StringWriter.write(writer, '#\n');
        }
        function writeLine(writer, val) {
            StringWriter.write(writer, val);
            StringWriter.newline(writer);
        }
        function writeInteger(writer, val) {
            StringWriter.writeSafe(writer, '' + val + ' ');
        }
        /**
            * eg writeFloat(123.2123, 100) -- 2 decim
            */
        function writeFloat(writer, val, precisionMultiplier) {
            StringWriter.writeSafe(writer, '' + Math.round(precisionMultiplier * val) / precisionMultiplier + ' ');
        }
        /**
            * Writes '. '
            */
        function writeNotSpecified(writer) {
            StringWriter.writeSafe(writer, '. ');
        }
        /**
            * Writes '? '
            */
        function writeUnknown(writer) {
            StringWriter.writeSafe(writer, '? ');
        }
        function writeChecked(writer, val) {
            if (!val) {
                StringWriter.writeSafe(writer, '. ');
                return;
            }
            var escape = false, escapeCharStart = '\'', escapeCharEnd = '\' ';
            var hasWhitespace = false;
            var hasSingle = false;
            var hasDouble = false;
            for (var i = 0, _l = val.length - 1; i < _l; i++) {
                var c = val.charCodeAt(i);
                switch (c) {
                    case 9:
                        hasWhitespace = true;
                        break; // \t
                    case 10:
                        StringWriter.writeSafe(writer, '\n;' + val);
                        StringWriter.writeSafe(writer, '\n; ');
                        return;
                    case 32:
                        hasWhitespace = true;
                        break; // ' '
                    case 34:
                        if (hasSingle) {
                            StringWriter.writeSafe(writer, '\n;' + val);
                            StringWriter.writeSafe(writer, '\n; ');
                            return;
                        }
                        hasDouble = true;
                        escape = true;
                        escapeCharStart = '\'';
                        escapeCharEnd = '\' ';
                        break;
                    case 39:
                        if (hasDouble) {
                            StringWriter.writeSafe(writer, '\n;' + val);
                            StringWriter.writeSafe(writer, '\n; ');
                            return;
                        }
                        escape = true;
                        hasSingle = true;
                        escapeCharStart = '"';
                        escapeCharEnd = '" ';
                        break;
                }
            }
            var fst = val.charCodeAt(0);
            if (!escape && (fst === 35 /* # */ || fst === 59 /* ; */ || hasWhitespace)) {
                escapeCharStart = '\'';
                escapeCharEnd = '\' ';
                escape = true;
            }
            if (escape) {
                StringWriter.writeSafe(writer, escapeCharStart + val + escapeCharEnd);
            }
            else {
                StringWriter.write(writer, val);
                StringWriter.writeSafe(writer, ' ');
            }
        }
        function writeMultiline(writer, val) {
            StringWriter.writeSafe(writer, '\n;' + val);
            StringWriter.writeSafe(writer, '\n; ');
        }
        function writeToken(writer, data, start, end) {
            var escape = false, escapeCharStart = '\'', escapeCharEnd = '\' ';
            for (var i = start; i < end - 1; i++) {
                var c = data.charCodeAt(i);
                switch (c) {
                    case 10:
                        StringWriter.writeSafe(writer, '\n;' + data.substring(start, end));
                        StringWriter.writeSafe(writer, '\n; ');
                        return;
                    case 34:
                        escape = true;
                        escapeCharStart = '\'';
                        escapeCharEnd = '\' ';
                        break;
                    case 39:
                        escape = true;
                        escapeCharStart = '"';
                        escapeCharEnd = '" ';
                        break;
                }
            }
            if (!escape && data.charCodeAt(start) === 59 /* ; */) {
                escapeCharStart = '\'';
                escapeCharEnd = '\' ';
                escape = true;
            }
            if (escape) {
                StringWriter.writeSafe(writer, escapeCharStart + data.substring(start, end));
                StringWriter.writeSafe(writer, escapeCharStart);
            }
            else {
                StringWriter.write(writer, data.substring(start, end));
                StringWriter.writeSafe(writer, ' ');
            }
        }
    })(Text = CIFTools.Text || (CIFTools.Text = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        var MessagePack;
        (function (MessagePack) {
            /*
             * Adapted from https://github.com/rcsb/mmtf-javascript
             * by Alexander Rose <alexander.rose@weirdbyte.de>, MIT License, Copyright (c) 2016
             */
            /**
             * decode all key-value pairs of a map into an object
             * @param  {Integer} length - number of key-value pairs
             * @return {Object} decoded map
             */
            function map(state, length) {
                var value = {};
                for (var i = 0; i < length; i++) {
                    var key = parse(state);
                    value[key] = parse(state);
                }
                return value;
            }
            /**
             * decode binary array
             * @param  {Integer} length - number of elements in the array
             * @return {Uint8Array} decoded array
             */
            function bin(state, length) {
                // This approach to binary parsing wastes a bit of memory to trade for speed compared to:
                //
                //   let value = buffer.subarray(offset, offset + length); //new Uint8Array(buffer.buffer, offset, length);
                // 
                // It turns out that using the view created by subarray probably uses DataView
                // in the background, which causes the element access to be several times slower
                // than creating the new byte array.
                var value = new Uint8Array(length);
                var o = state.offset;
                for (var i = 0; i < length; i++)
                    value[i] = state.buffer[i + o];
                state.offset += length;
                return value;
            }
            /**
             * decode string
             * @param  {Integer} length - number string characters
             * @return {String} decoded string
             */
            function str(state, length) {
                var value = MessagePack.utf8Read(state.buffer, state.offset, length);
                state.offset += length;
                return value;
            }
            /**
                 * decode array
                 * @param  {Integer} length - number of array elements
                 * @return {Array} decoded array
                 */
            function array(state, length) {
                var value = new Array(length);
                for (var i = 0; i < length; i++) {
                    value[i] = parse(state);
                }
                return value;
            }
            /**
             * recursively parse the MessagePack data
             * @return {Object|Array|String|Number|Boolean|null} decoded MessagePack data
             */
            function parse(state) {
                var type = state.buffer[state.offset];
                var value, length;
                // Positive FixInt
                if ((type & 0x80) === 0x00) {
                    state.offset++;
                    return type;
                }
                // FixMap
                if ((type & 0xf0) === 0x80) {
                    length = type & 0x0f;
                    state.offset++;
                    return map(state, length);
                }
                // FixArray
                if ((type & 0xf0) === 0x90) {
                    length = type & 0x0f;
                    state.offset++;
                    return array(state, length);
                }
                // FixStr
                if ((type & 0xe0) === 0xa0) {
                    length = type & 0x1f;
                    state.offset++;
                    return str(state, length);
                }
                // Negative FixInt
                if ((type & 0xe0) === 0xe0) {
                    value = state.dataView.getInt8(state.offset);
                    state.offset++;
                    return value;
                }
                switch (type) {
                    // nil
                    case 0xc0:
                        state.offset++;
                        return null;
                    // false
                    case 0xc2:
                        state.offset++;
                        return false;
                    // true
                    case 0xc3:
                        state.offset++;
                        return true;
                    // bin 8
                    case 0xc4:
                        length = state.dataView.getUint8(state.offset + 1);
                        state.offset += 2;
                        return bin(state, length);
                    // bin 16
                    case 0xc5:
                        length = state.dataView.getUint16(state.offset + 1);
                        state.offset += 3;
                        return bin(state, length);
                    // bin 32
                    case 0xc6:
                        length = state.dataView.getUint32(state.offset + 1);
                        state.offset += 5;
                        return bin(state, length);
                    // float 32
                    case 0xca:
                        value = state.dataView.getFloat32(state.offset + 1);
                        state.offset += 5;
                        return value;
                    // float 64
                    case 0xcb:
                        value = state.dataView.getFloat64(state.offset + 1);
                        state.offset += 9;
                        return value;
                    // uint8
                    case 0xcc:
                        value = state.buffer[state.offset + 1];
                        state.offset += 2;
                        return value;
                    // uint 16
                    case 0xcd:
                        value = state.dataView.getUint16(state.offset + 1);
                        state.offset += 3;
                        return value;
                    // uint 32
                    case 0xce:
                        value = state.dataView.getUint32(state.offset + 1);
                        state.offset += 5;
                        return value;
                    // int 8
                    case 0xd0:
                        value = state.dataView.getInt8(state.offset + 1);
                        state.offset += 2;
                        return value;
                    // int 16
                    case 0xd1:
                        value = state.dataView.getInt16(state.offset + 1);
                        state.offset += 3;
                        return value;
                    // int 32
                    case 0xd2:
                        value = state.dataView.getInt32(state.offset + 1);
                        state.offset += 5;
                        return value;
                    // str 8
                    case 0xd9:
                        length = state.dataView.getUint8(state.offset + 1);
                        state.offset += 2;
                        return str(state, length);
                    // str 16
                    case 0xda:
                        length = state.dataView.getUint16(state.offset + 1);
                        state.offset += 3;
                        return str(state, length);
                    // str 32
                    case 0xdb:
                        length = state.dataView.getUint32(state.offset + 1);
                        state.offset += 5;
                        return str(state, length);
                    // array 16
                    case 0xdc:
                        length = state.dataView.getUint16(state.offset + 1);
                        state.offset += 3;
                        return array(state, length);
                    // array 32
                    case 0xdd:
                        length = state.dataView.getUint32(state.offset + 1);
                        state.offset += 5;
                        return array(state, length);
                    // map 16:
                    case 0xde:
                        length = state.dataView.getUint16(state.offset + 1);
                        state.offset += 3;
                        return map(state, length);
                    // map 32
                    case 0xdf:
                        length = state.dataView.getUint32(state.offset + 1);
                        state.offset += 5;
                        return map(state, length);
                }
                throw new Error("Unknown type 0x" + type.toString(16));
            }
            function decode(buffer) {
                return parse({
                    buffer: buffer,
                    offset: 0,
                    dataView: new DataView(buffer.buffer)
                });
            }
            MessagePack.decode = decode;
        })(MessagePack = Binary.MessagePack || (Binary.MessagePack = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        var MessagePack;
        (function (MessagePack) {
            /*
             * Adapted from https://github.com/rcsb/mmtf-javascript
             * by Alexander Rose <alexander.rose@weirdbyte.de>, MIT License, Copyright (c) 2016
             */
            function encode(value) {
                var buffer = new ArrayBuffer(encodedSize(value));
                var view = new DataView(buffer);
                var bytes = new Uint8Array(buffer);
                encodeInternal(value, view, bytes, 0);
                return bytes;
            }
            MessagePack.encode = encode;
            function encodedSize(value) {
                var type = typeof value;
                // Raw Bytes
                if (type === "string") {
                    var length_1 = MessagePack.utf8ByteCount(value);
                    if (length_1 < 0x20) {
                        return 1 + length_1;
                    }
                    if (length_1 < 0x100) {
                        return 2 + length_1;
                    }
                    if (length_1 < 0x10000) {
                        return 3 + length_1;
                    }
                    if (length_1 < 0x100000000) {
                        return 5 + length_1;
                    }
                }
                if (value instanceof Uint8Array) {
                    var length_2 = value.byteLength;
                    if (length_2 < 0x100) {
                        return 2 + length_2;
                    }
                    if (length_2 < 0x10000) {
                        return 3 + length_2;
                    }
                    if (length_2 < 0x100000000) {
                        return 5 + length_2;
                    }
                }
                if (type === "number") {
                    // Floating Point
                    // double
                    if (Math.floor(value) !== value)
                        return 9;
                    // Integers
                    if (value >= 0) {
                        // positive fixnum
                        if (value < 0x80)
                            return 1;
                        // uint 8
                        if (value < 0x100)
                            return 2;
                        // uint 16
                        if (value < 0x10000)
                            return 3;
                        // uint 32
                        if (value < 0x100000000)
                            return 5;
                        throw new Error("Number too big 0x" + value.toString(16));
                    }
                    // negative fixnum
                    if (value >= -0x20)
                        return 1;
                    // int 8
                    if (value >= -0x80)
                        return 2;
                    // int 16
                    if (value >= -0x8000)
                        return 3;
                    // int 32
                    if (value >= -0x80000000)
                        return 5;
                    throw new Error("Number too small -0x" + value.toString(16).substr(1));
                }
                // Boolean, null
                if (type === "boolean" || value === null || value === void 0)
                    return 1;
                // Container Types
                if (type === "object") {
                    var length_3, size = 0;
                    if (Array.isArray(value)) {
                        length_3 = value.length;
                        for (var i = 0; i < length_3; i++) {
                            size += encodedSize(value[i]);
                        }
                    }
                    else {
                        var keys = Object.keys(value);
                        length_3 = keys.length;
                        for (var i = 0; i < length_3; i++) {
                            var key = keys[i];
                            size += encodedSize(key) + encodedSize(value[key]);
                        }
                    }
                    if (length_3 < 0x10) {
                        return 1 + size;
                    }
                    if (length_3 < 0x10000) {
                        return 3 + size;
                    }
                    if (length_3 < 0x100000000) {
                        return 5 + size;
                    }
                    throw new Error("Array or object too long 0x" + length_3.toString(16));
                }
                throw new Error("Unknown type " + type);
            }
            function encodeInternal(value, view, bytes, offset) {
                var type = typeof value;
                // Strings Bytes
                if (type === "string") {
                    var length_4 = MessagePack.utf8ByteCount(value);
                    // fix str
                    if (length_4 < 0x20) {
                        view.setUint8(offset, length_4 | 0xa0);
                        MessagePack.utf8Write(bytes, offset + 1, value);
                        return 1 + length_4;
                    }
                    // str 8
                    if (length_4 < 0x100) {
                        view.setUint8(offset, 0xd9);
                        view.setUint8(offset + 1, length_4);
                        MessagePack.utf8Write(bytes, offset + 2, value);
                        return 2 + length_4;
                    }
                    // str 16
                    if (length_4 < 0x10000) {
                        view.setUint8(offset, 0xda);
                        view.setUint16(offset + 1, length_4);
                        MessagePack.utf8Write(bytes, offset + 3, value);
                        return 3 + length_4;
                    }
                    // str 32
                    if (length_4 < 0x100000000) {
                        view.setUint8(offset, 0xdb);
                        view.setUint32(offset + 1, length_4);
                        MessagePack.utf8Write(bytes, offset + 5, value);
                        return 5 + length_4;
                    }
                }
                if (value instanceof Uint8Array) {
                    var length_5 = value.byteLength;
                    var bytes_1 = new Uint8Array(view.buffer);
                    // bin 8
                    if (length_5 < 0x100) {
                        view.setUint8(offset, 0xc4);
                        view.setUint8(offset + 1, length_5);
                        bytes_1.set(value, offset + 2);
                        return 2 + length_5;
                    }
                    // bin 16
                    if (length_5 < 0x10000) {
                        view.setUint8(offset, 0xc5);
                        view.setUint16(offset + 1, length_5);
                        bytes_1.set(value, offset + 3);
                        return 3 + length_5;
                    }
                    // bin 32
                    if (length_5 < 0x100000000) {
                        view.setUint8(offset, 0xc6);
                        view.setUint32(offset + 1, length_5);
                        bytes_1.set(value, offset + 5);
                        return 5 + length_5;
                    }
                }
                if (type === "number") {
                    if (!isFinite(value)) {
                        throw new Error("Number not finite: " + value);
                    }
                    // Floating point
                    if (Math.floor(value) !== value) {
                        view.setUint8(offset, 0xcb);
                        view.setFloat64(offset + 1, value);
                        return 9;
                    }
                    // Integers
                    if (value >= 0) {
                        // positive fixnum
                        if (value < 0x80) {
                            view.setUint8(offset, value);
                            return 1;
                        }
                        // uint 8
                        if (value < 0x100) {
                            view.setUint8(offset, 0xcc);
                            view.setUint8(offset + 1, value);
                            return 2;
                        }
                        // uint 16
                        if (value < 0x10000) {
                            view.setUint8(offset, 0xcd);
                            view.setUint16(offset + 1, value);
                            return 3;
                        }
                        // uint 32
                        if (value < 0x100000000) {
                            view.setUint8(offset, 0xce);
                            view.setUint32(offset + 1, value);
                            return 5;
                        }
                        throw new Error("Number too big 0x" + value.toString(16));
                    }
                    // negative fixnum
                    if (value >= -0x20) {
                        view.setInt8(offset, value);
                        return 1;
                    }
                    // int 8
                    if (value >= -0x80) {
                        view.setUint8(offset, 0xd0);
                        view.setInt8(offset + 1, value);
                        return 2;
                    }
                    // int 16
                    if (value >= -0x8000) {
                        view.setUint8(offset, 0xd1);
                        view.setInt16(offset + 1, value);
                        return 3;
                    }
                    // int 32
                    if (value >= -0x80000000) {
                        view.setUint8(offset, 0xd2);
                        view.setInt32(offset + 1, value);
                        return 5;
                    }
                    throw new Error("Number too small -0x" + (-value).toString(16).substr(1));
                }
                // null
                if (value === null || value === undefined) {
                    view.setUint8(offset, 0xc0);
                    return 1;
                }
                // Boolean
                if (type === "boolean") {
                    view.setUint8(offset, value ? 0xc3 : 0xc2);
                    return 1;
                }
                // Container Types
                if (type === "object") {
                    var length_6, size = 0;
                    var isArray = Array.isArray(value);
                    var keys = void 0;
                    if (isArray) {
                        length_6 = value.length;
                    }
                    else {
                        keys = Object.keys(value);
                        length_6 = keys.length;
                    }
                    if (length_6 < 0x10) {
                        view.setUint8(offset, length_6 | (isArray ? 0x90 : 0x80));
                        size = 1;
                    }
                    else if (length_6 < 0x10000) {
                        view.setUint8(offset, isArray ? 0xdc : 0xde);
                        view.setUint16(offset + 1, length_6);
                        size = 3;
                    }
                    else if (length_6 < 0x100000000) {
                        view.setUint8(offset, isArray ? 0xdd : 0xdf);
                        view.setUint32(offset + 1, length_6);
                        size = 5;
                    }
                    if (isArray) {
                        for (var i = 0; i < length_6; i++) {
                            size += encodeInternal(value[i], view, bytes, offset + size);
                        }
                    }
                    else {
                        for (var _i = 0, _a = keys; _i < _a.length; _i++) {
                            var key = _a[_i];
                            size += encodeInternal(key, view, bytes, offset + size);
                            size += encodeInternal(value[key], view, bytes, offset + size);
                        }
                    }
                    return size;
                }
                throw new Error("Unknown type " + type);
            }
        })(MessagePack = Binary.MessagePack || (Binary.MessagePack = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        var MessagePack;
        (function (MessagePack) {
            /*
             * Adapted from https://github.com/rcsb/mmtf-javascript
             * by Alexander Rose <alexander.rose@weirdbyte.de>, MIT License, Copyright (c) 2016
             */
            function utf8Write(data, offset, str) {
                var byteLength = data.byteLength;
                for (var i = 0, l = str.length; i < l; i++) {
                    var codePoint = str.charCodeAt(i);
                    // One byte of UTF-8
                    if (codePoint < 0x80) {
                        data[offset++] = codePoint >>> 0 & 0x7f | 0x00;
                        continue;
                    }
                    // Two bytes of UTF-8
                    if (codePoint < 0x800) {
                        data[offset++] = codePoint >>> 6 & 0x1f | 0xc0;
                        data[offset++] = codePoint >>> 0 & 0x3f | 0x80;
                        continue;
                    }
                    // Three bytes of UTF-8.
                    if (codePoint < 0x10000) {
                        data[offset++] = codePoint >>> 12 & 0x0f | 0xe0;
                        data[offset++] = codePoint >>> 6 & 0x3f | 0x80;
                        data[offset++] = codePoint >>> 0 & 0x3f | 0x80;
                        continue;
                    }
                    // Four bytes of UTF-8
                    if (codePoint < 0x110000) {
                        data[offset++] = codePoint >>> 18 & 0x07 | 0xf0;
                        data[offset++] = codePoint >>> 12 & 0x3f | 0x80;
                        data[offset++] = codePoint >>> 6 & 0x3f | 0x80;
                        data[offset++] = codePoint >>> 0 & 0x3f | 0x80;
                        continue;
                    }
                    throw new Error("bad codepoint " + codePoint);
                }
            }
            MessagePack.utf8Write = utf8Write;
            var __chars = function () {
                var data = [];
                for (var i = 0; i < 1024; i++)
                    data[i] = String.fromCharCode(i);
                return data;
            }();
            function throwError(err) {
                throw new Error(err);
            }
            function utf8Read(data, offset, length) {
                var chars = __chars;
                var str = void 0, chunk = [], chunkSize = 512, chunkOffset = 0;
                for (var i = offset, end = offset + length; i < end; i++) {
                    var byte = data[i];
                    // One byte character
                    if ((byte & 0x80) === 0x00) {
                        chunk[chunkOffset++] = chars[byte];
                    }
                    else if ((byte & 0xe0) === 0xc0) {
                        chunk[chunkOffset++] = chars[((byte & 0x0f) << 6) | (data[++i] & 0x3f)];
                    }
                    else if ((byte & 0xf0) === 0xe0) {
                        chunk[chunkOffset++] = String.fromCharCode(((byte & 0x0f) << 12) |
                            ((data[++i] & 0x3f) << 6) |
                            ((data[++i] & 0x3f) << 0));
                    }
                    else if ((byte & 0xf8) === 0xf0) {
                        chunk[chunkOffset++] = String.fromCharCode(((byte & 0x07) << 18) |
                            ((data[++i] & 0x3f) << 12) |
                            ((data[++i] & 0x3f) << 6) |
                            ((data[++i] & 0x3f) << 0));
                    }
                    else
                        throwError("Invalid byte " + byte.toString(16));
                    if (chunkOffset === chunkSize) {
                        str = str || [];
                        str[str.length] = chunk.join('');
                        chunkOffset = 0;
                    }
                }
                if (!str)
                    return chunk.slice(0, chunkOffset).join('');
                if (chunkOffset > 0) {
                    str[str.length] = chunk.slice(0, chunkOffset).join('');
                }
                return str.join('');
            }
            MessagePack.utf8Read = utf8Read;
            function utf8ByteCount(str) {
                var count = 0;
                for (var i = 0, l = str.length; i < l; i++) {
                    var codePoint = str.charCodeAt(i);
                    if (codePoint < 0x80) {
                        count += 1;
                        continue;
                    }
                    if (codePoint < 0x800) {
                        count += 2;
                        continue;
                    }
                    if (codePoint < 0x10000) {
                        count += 3;
                        continue;
                    }
                    if (codePoint < 0x110000) {
                        count += 4;
                        continue;
                    }
                    throwError("bad codepoint " + codePoint);
                }
                return count;
            }
            MessagePack.utf8ByteCount = utf8ByteCount;
        })(MessagePack = Binary.MessagePack || (Binary.MessagePack = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        /**
         * Fixed point, delta, RLE, integer packing adopted from https://github.com/rcsb/mmtf-javascript/
         * by Alexander Rose <alexander.rose@weirdbyte.de>, MIT License, Copyright (c) 2016
         */
        function decode(data) {
            var current = data.data;
            for (var i = data.encoding.length - 1; i >= 0; i--) {
                current = Decoder.decodeStep(current, data.encoding[i]);
            }
            return current;
        }
        Binary.decode = decode;
        var Decoder;
        (function (Decoder) {
            function decodeStep(data, encoding) {
                switch (encoding.kind) {
                    case 'ByteArray': {
                        switch (encoding.type) {
                            case 4 /* Uint8 */: return data;
                            case 1 /* Int8 */: return int8(data);
                            case 2 /* Int16 */: return int16(data);
                            case 5 /* Uint16 */: return uint16(data);
                            case 3 /* Int32 */: return int32(data);
                            case 6 /* Uint32 */: return uint32(data);
                            case 32 /* Float32 */: return float32(data);
                            case 33 /* Float64 */: return float64(data);
                            default: throw new Error('Unsupported ByteArray type.');
                        }
                    }
                    case 'FixedPoint': return fixedPoint(data, encoding);
                    case 'IntervalQuantization': return intervalQuantization(data, encoding);
                    case 'RunLength': return runLength(data, encoding);
                    case 'Delta': return delta(data, encoding);
                    case 'IntegerPacking': return integerPacking(data, encoding);
                    case 'StringArray': return stringArray(data, encoding);
                }
            }
            Decoder.decodeStep = decodeStep;
            function getIntArray(type, size) {
                switch (type) {
                    case 1 /* Int8 */: return new Int8Array(size);
                    case 2 /* Int16 */: return new Int16Array(size);
                    case 3 /* Int32 */: return new Int32Array(size);
                    case 4 /* Uint8 */: return new Uint8Array(size);
                    case 5 /* Uint16 */: return new Uint16Array(size);
                    case 6 /* Uint32 */: return new Uint32Array(size);
                    default: throw new Error('Unsupported integer data type.');
                }
            }
            function getFloatArray(type, size) {
                switch (type) {
                    case 32 /* Float32 */: return new Float32Array(size);
                    case 33 /* Float64 */: return new Float64Array(size);
                    default: throw new Error('Unsupported floating data type.');
                }
            }
            /* http://stackoverflow.com/questions/7869752/javascript-typed-arrays-and-endianness */
            var isLittleEndian = (function () {
                var arrayBuffer = new ArrayBuffer(2);
                var uint8Array = new Uint8Array(arrayBuffer);
                var uint16array = new Uint16Array(arrayBuffer);
                uint8Array[0] = 0xAA;
                uint8Array[1] = 0xBB;
                if (uint16array[0] === 0xBBAA)
                    return true;
                return false;
            })();
            function int8(data) { return new Int8Array(data.buffer, data.byteOffset); }
            function flipByteOrder(data, bytes) {
                var buffer = new ArrayBuffer(data.length);
                var ret = new Uint8Array(buffer);
                for (var i = 0, n = data.length; i < n; i += bytes) {
                    for (var j = 0; j < bytes; j++) {
                        ret[i + bytes - j - 1] = data[i + j];
                    }
                }
                return buffer;
            }
            function view(data, byteSize, c) {
                if (isLittleEndian)
                    return new c(data.buffer);
                return new c(flipByteOrder(data, byteSize));
            }
            function int16(data) { return view(data, 2, Int16Array); }
            function uint16(data) { return view(data, 2, Uint16Array); }
            function int32(data) { return view(data, 4, Int32Array); }
            function uint32(data) { return view(data, 4, Uint32Array); }
            function float32(data) { return view(data, 4, Float32Array); }
            function float64(data) { return view(data, 8, Float64Array); }
            function fixedPoint(data, encoding) {
                var n = data.length;
                var output = getFloatArray(encoding.srcType, n);
                var f = 1 / encoding.factor;
                for (var i = 0; i < n; i++) {
                    output[i] = f * data[i];
                }
                return output;
            }
            function intervalQuantization(data, encoding) {
                var n = data.length;
                var output = getFloatArray(encoding.srcType, n);
                var delta = (encoding.max - encoding.min) / (encoding.numSteps - 1);
                var min = encoding.min;
                for (var i = 0; i < n; i++) {
                    output[i] = min + delta * data[i];
                }
                return output;
            }
            function runLength(data, encoding) {
                var output = getIntArray(encoding.srcType, encoding.srcSize);
                var dataOffset = 0;
                for (var i = 0, il = data.length; i < il; i += 2) {
                    var value = data[i]; // value to be repeated
                    var length_7 = data[i + 1]; // number of repeats
                    for (var j = 0; j < length_7; ++j) {
                        output[dataOffset++] = value;
                    }
                }
                return output;
            }
            function delta(data, encoding) {
                var n = data.length;
                var output = getIntArray(encoding.srcType, n);
                if (!n)
                    return output;
                output[0] = data[0] + (encoding.origin | 0);
                for (var i = 1; i < n; ++i) {
                    output[i] = data[i] + output[i - 1];
                }
                return output;
            }
            function integerPackingSigned(data, encoding) {
                var upperLimit = encoding.byteCount === 1 ? 0x7F : 0x7FFF;
                var lowerLimit = -upperLimit - 1;
                var n = data.length;
                var output = new Int32Array(encoding.srcSize);
                var i = 0;
                var j = 0;
                while (i < n) {
                    var value = 0, t = data[i];
                    while (t === upperLimit || t === lowerLimit) {
                        value += t;
                        i++;
                        t = data[i];
                    }
                    value += t;
                    output[j] = value;
                    i++;
                    j++;
                }
                return output;
            }
            function integerPackingUnsigned(data, encoding) {
                var upperLimit = encoding.byteCount === 1 ? 0xFF : 0xFFFF;
                var n = data.length;
                var output = new Int32Array(encoding.srcSize);
                var i = 0;
                var j = 0;
                while (i < n) {
                    var value = 0, t = data[i];
                    while (t === upperLimit) {
                        value += t;
                        i++;
                        t = data[i];
                    }
                    value += t;
                    output[j] = value;
                    i++;
                    j++;
                }
                return output;
            }
            function integerPacking(data, encoding) {
                return encoding.isUnsigned ? integerPackingUnsigned(data, encoding) : integerPackingSigned(data, encoding);
            }
            function stringArray(data, encoding) {
                var str = encoding.stringData;
                var offsets = decode({ encoding: encoding.offsetEncoding, data: encoding.offsets });
                var indices = decode({ encoding: encoding.dataEncoding, data: data });
                var cache = Object.create(null);
                var result = new Array(indices.length);
                var offset = 0;
                for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
                    var i = indices_1[_i];
                    if (i < 0) {
                        result[offset++] = null;
                        continue;
                    }
                    var v = cache[i];
                    if (v === void 0) {
                        v = str.substring(offsets[i], offsets[i + 1]);
                        cache[i] = v;
                    }
                    result[offset++] = v;
                }
                return result;
            }
        })(Decoder || (Decoder = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        var File = (function () {
            function File(data) {
                this.dataBlocks = data.dataBlocks.map(function (b) { return new DataBlock(b); });
            }
            File.prototype.toJSON = function () {
                return this.dataBlocks.map(function (b) { return b.toJSON(); });
            };
            return File;
        }());
        Binary.File = File;
        var DataBlock = (function () {
            function DataBlock(data) {
                this.additionalData = {};
                this.header = data.header;
                this.categoryList = data.categories.map(function (c) { return new Category(c); });
                this.categoryMap = new Map();
                for (var _i = 0, _a = this.categoryList; _i < _a.length; _i++) {
                    var c = _a[_i];
                    this.categoryMap.set(c.name, c);
                }
            }
            Object.defineProperty(DataBlock.prototype, "categories", {
                get: function () { return this.categoryList; },
                enumerable: true,
                configurable: true
            });
            DataBlock.prototype.getCategory = function (name) { return this.categoryMap.get(name); };
            DataBlock.prototype.toJSON = function () {
                return {
                    id: this.header,
                    categories: this.categoryList.map(function (c) { return c.toJSON(); }),
                    additionalData: this.additionalData
                };
            };
            return DataBlock;
        }());
        Binary.DataBlock = DataBlock;
        var Category = (function () {
            function Category(data) {
                this.name = data.name;
                this.columnCount = data.columns.length;
                this.rowCount = data.rowCount;
                this.columnNameList = [];
                this.encodedColumns = new Map();
                for (var _i = 0, _a = data.columns; _i < _a.length; _i++) {
                    var c = _a[_i];
                    this.encodedColumns.set(c.name, c);
                    this.columnNameList.push(c.name);
                }
            }
            Object.defineProperty(Category.prototype, "columnNames", {
                get: function () { return this.columnNameList; },
                enumerable: true,
                configurable: true
            });
            Category.prototype.getColumn = function (name) {
                var w = this.encodedColumns.get(name);
                if (w)
                    return wrapColumn(w);
                return CIFTools.UndefinedColumn;
            };
            Category.prototype.toJSON = function () {
                var _this = this;
                var rows = [];
                var columns = this.columnNameList.map(function (name) { return ({ name: name, column: _this.getColumn(name) }); });
                for (var i = 0; i < this.rowCount; i++) {
                    var item = {};
                    for (var _i = 0, columns_1 = columns; _i < columns_1.length; _i++) {
                        var c = columns_1[_i];
                        var d = c.column.getValuePresence(i);
                        if (d === 0 /* Present */)
                            item[c.name] = c.column.getString(i);
                        else if (d === 1 /* NotSpecified */)
                            item[c.name] = '.';
                        else
                            item[c.name] = '?';
                    }
                    rows[i] = item;
                }
                return { name: this.name, columns: this.columnNames, rows: rows };
            };
            return Category;
        }());
        Binary.Category = Category;
        function wrapColumn(column) {
            if (!column.data.data)
                return CIFTools.UndefinedColumn;
            var data = Binary.decode(column.data);
            var mask = void 0;
            if (column.mask)
                mask = Binary.decode(column.mask);
            if (data.buffer && data.byteLength && data.BYTES_PER_ELEMENT) {
                return mask ? new MaskedNumericColumn(data, mask) : new NumericColumn(data);
            }
            return mask ? new MaskedStringColumn(data, mask) : new StringColumn(data);
        }
        var fastParseInt = CIFTools.Utils.FastNumberParsers.parseInt;
        var fastParseFloat = CIFTools.Utils.FastNumberParsers.parseFloat;
        var NumericColumn = (function () {
            function NumericColumn(data) {
                this.data = data;
                this.isDefined = true;
            }
            NumericColumn.prototype.getString = function (row) { return "" + this.data[row]; };
            NumericColumn.prototype.getInteger = function (row) { return this.data[row] | 0; };
            NumericColumn.prototype.getFloat = function (row) { return 1.0 * this.data[row]; };
            NumericColumn.prototype.stringEquals = function (row, value) { return this.data[row] === fastParseFloat(value, 0, value.length); };
            NumericColumn.prototype.areValuesEqual = function (rowA, rowB) { return this.data[rowA] === this.data[rowB]; };
            NumericColumn.prototype.getValuePresence = function (row) { return 0 /* Present */; };
            return NumericColumn;
        }());
        var MaskedNumericColumn = (function () {
            function MaskedNumericColumn(data, mask) {
                this.data = data;
                this.mask = mask;
                this.isDefined = true;
            }
            MaskedNumericColumn.prototype.getString = function (row) { return this.mask[row] === 0 /* Present */ ? "" + this.data[row] : null; };
            MaskedNumericColumn.prototype.getInteger = function (row) { return this.mask[row] === 0 /* Present */ ? this.data[row] : 0; };
            MaskedNumericColumn.prototype.getFloat = function (row) { return this.mask[row] === 0 /* Present */ ? this.data[row] : 0; };
            MaskedNumericColumn.prototype.stringEquals = function (row, value) { return this.mask[row] === 0 /* Present */ ? this.data[row] === fastParseFloat(value, 0, value.length) : value === null || value === void 0; };
            MaskedNumericColumn.prototype.areValuesEqual = function (rowA, rowB) { return this.data[rowA] === this.data[rowB]; };
            MaskedNumericColumn.prototype.getValuePresence = function (row) { return this.mask[row]; };
            return MaskedNumericColumn;
        }());
        var StringColumn = (function () {
            function StringColumn(data) {
                this.data = data;
                this.isDefined = true;
            }
            StringColumn.prototype.getString = function (row) { return this.data[row]; };
            StringColumn.prototype.getInteger = function (row) { var v = this.data[row]; return fastParseInt(v, 0, v.length); };
            StringColumn.prototype.getFloat = function (row) { var v = this.data[row]; return fastParseFloat(v, 0, v.length); };
            StringColumn.prototype.stringEquals = function (row, value) { return this.data[row] === value; };
            StringColumn.prototype.areValuesEqual = function (rowA, rowB) { return this.data[rowA] === this.data[rowB]; };
            StringColumn.prototype.getValuePresence = function (row) { return 0 /* Present */; };
            return StringColumn;
        }());
        var MaskedStringColumn = (function () {
            function MaskedStringColumn(data, mask) {
                this.data = data;
                this.mask = mask;
                this.isDefined = true;
            }
            MaskedStringColumn.prototype.getString = function (row) { return this.mask[row] === 0 /* Present */ ? this.data[row] : null; };
            MaskedStringColumn.prototype.getInteger = function (row) { if (this.mask[row] !== 0 /* Present */)
                return 0; var v = this.data[row]; return fastParseInt(v || '', 0, (v || '').length); };
            MaskedStringColumn.prototype.getFloat = function (row) { if (this.mask[row] !== 0 /* Present */)
                return 0; var v = this.data[row]; return fastParseFloat(v || '', 0, (v || '').length); };
            MaskedStringColumn.prototype.stringEquals = function (row, value) { return this.data[row] === value; };
            MaskedStringColumn.prototype.areValuesEqual = function (rowA, rowB) { return this.data[rowA] === this.data[rowB]; };
            MaskedStringColumn.prototype.getValuePresence = function (row) { return this.mask[row]; };
            return MaskedStringColumn;
        }());
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        /**
         * Fixed point, delta, RLE, integer packing adopted from https://github.com/rcsb/mmtf-javascript/
         * by Alexander Rose <alexander.rose@weirdbyte.de>, MIT License, Copyright (c) 2016
         */
        var Encoder = (function () {
            function Encoder(providers) {
                this.providers = providers;
            }
            Encoder.prototype.and = function (f) {
                return new Encoder(this.providers.concat([f]));
            };
            Encoder.prototype.encode = function (data) {
                var encoding = [];
                for (var _i = 0, _a = this.providers; _i < _a.length; _i++) {
                    var p = _a[_i];
                    var t = p(data);
                    if (!t.encodings.length) {
                        throw new Error('Encodings must be non-empty.');
                    }
                    data = t.data;
                    for (var _b = 0, _c = t.encodings; _b < _c.length; _b++) {
                        var e = _c[_b];
                        encoding.push(e);
                    }
                }
                if (!(data instanceof Uint8Array)) {
                    throw new Error('The encoding must result in a Uint8Array. Fix your encoding chain.');
                }
                return {
                    encoding: encoding,
                    data: data
                };
            };
            return Encoder;
        }());
        Binary.Encoder = Encoder;
        (function (Encoder) {
            function by(f) {
                return new Encoder([f]);
            }
            Encoder.by = by;
            function uint8(data) {
                return {
                    encodings: [{ kind: 'ByteArray', type: 4 /* Uint8 */ }],
                    data: data
                };
            }
            function int8(data) {
                return {
                    encodings: [{ kind: 'ByteArray', type: 1 /* Int8 */ }],
                    data: new Uint8Array(data.buffer, data.byteOffset)
                };
            }
            var writers = (_a = {},
                _a[2 /* Int16 */] = function (v, i, a) { v.setInt16(2 * i, a, true); },
                _a[5 /* Uint16 */] = function (v, i, a) { v.setUint16(2 * i, a, true); },
                _a[3 /* Int32 */] = function (v, i, a) { v.setInt32(4 * i, a, true); },
                _a[6 /* Uint32 */] = function (v, i, a) { v.setUint32(4 * i, a, true); },
                _a[32 /* Float32 */] = function (v, i, a) { v.setFloat32(4 * i, a, true); },
                _a[33 /* Float64 */] = function (v, i, a) { v.setFloat64(8 * i, a, true); },
                _a);
            var byteSizes = (_b = {},
                _b[2 /* Int16 */] = 2,
                _b[5 /* Uint16 */] = 2,
                _b[3 /* Int32 */] = 4,
                _b[6 /* Uint32 */] = 4,
                _b[32 /* Float32 */] = 4,
                _b[33 /* Float64 */] = 8,
                _b);
            function byteArray(data) {
                var type = Binary.Encoding.getDataType(data);
                if (type === 1 /* Int8 */)
                    return int8(data);
                else if (type === 4 /* Uint8 */)
                    return uint8(data);
                var result = new Uint8Array(data.length * byteSizes[type]);
                var w = writers[type];
                var view = new DataView(result.buffer);
                for (var i = 0, n = data.length; i < n; i++) {
                    w(view, i, data[i]);
                }
                return {
                    encodings: [{ kind: 'ByteArray', type: type }],
                    data: result
                };
            }
            Encoder.byteArray = byteArray;
            function _fixedPoint(data, factor) {
                var srcType = Binary.Encoding.getDataType(data);
                var result = new Int32Array(data.length);
                for (var i = 0, n = data.length; i < n; i++) {
                    result[i] = Math.round(data[i] * factor);
                }
                return {
                    encodings: [{ kind: 'FixedPoint', factor: factor, srcType: srcType }],
                    data: result
                };
            }
            function fixedPoint(factor) { return function (data) { return _fixedPoint(data, factor); }; }
            Encoder.fixedPoint = fixedPoint;
            function _intervalQuantizaiton(data, min, max, numSteps, arrayType) {
                var srcType = Binary.Encoding.getDataType(data);
                if (!data.length) {
                    return {
                        encodings: [{ kind: 'IntervalQuantization', min: min, max: max, numSteps: numSteps, srcType: srcType }],
                        data: new Int32Array(0)
                    };
                }
                if (max < min) {
                    var t = min;
                    min = max;
                    max = t;
                }
                var delta = (max - min) / (numSteps - 1);
                var output = new arrayType(data.length);
                for (var i = 0, n = data.length; i < n; i++) {
                    var v = data[i];
                    if (v <= min)
                        output[i] = 0;
                    else if (v >= max)
                        output[i] = numSteps;
                    else
                        output[i] = (Math.round((v - min) / delta)) | 0;
                }
                return {
                    encodings: [{ kind: 'IntervalQuantization', min: min, max: max, numSteps: numSteps, srcType: srcType }],
                    data: output
                };
            }
            function intervalQuantizaiton(min, max, numSteps, arrayType) {
                if (arrayType === void 0) { arrayType = Int32Array; }
                return function (data) { return _intervalQuantizaiton(data, min, max, numSteps, arrayType); };
            }
            Encoder.intervalQuantizaiton = intervalQuantizaiton;
            function runLength(data) {
                var srcType = Binary.Encoding.getDataType(data);
                if (srcType === void 0) {
                    data = new Int32Array(data);
                    srcType = 3 /* Int32 */;
                }
                if (!data.length) {
                    return {
                        encodings: [{ kind: 'RunLength', srcType: srcType, srcSize: 0 }],
                        data: new Int32Array(0)
                    };
                }
                // calculate output size
                var fullLength = 2;
                for (var i = 1, il = data.length; i < il; i++) {
                    if (data[i - 1] !== data[i]) {
                        fullLength += 2;
                    }
                }
                var output = new Int32Array(fullLength);
                var offset = 0;
                var runLength = 1;
                for (var i = 1, il = data.length; i < il; i++) {
                    if (data[i - 1] !== data[i]) {
                        output[offset] = data[i - 1];
                        output[offset + 1] = runLength;
                        runLength = 1;
                        offset += 2;
                    }
                    else {
                        ++runLength;
                    }
                }
                output[offset] = data[data.length - 1];
                output[offset + 1] = runLength;
                return {
                    encodings: [{ kind: 'RunLength', srcType: srcType, srcSize: data.length }],
                    data: output
                };
            }
            Encoder.runLength = runLength;
            function delta(data) {
                if (!Binary.Encoding.isSignedIntegerDataType(data)) {
                    throw new Error('Only signed integer types can be encoded using delta encoding.');
                }
                var srcType = Binary.Encoding.getDataType(data);
                if (srcType === void 0) {
                    data = new Int32Array(data);
                    srcType = 3 /* Int32 */;
                }
                if (!data.length) {
                    return {
                        encodings: [{ kind: 'Delta', origin: 0, srcType: srcType }],
                        data: new data.constructor(0)
                    };
                }
                var output = new data.constructor(data.length);
                var origin = data[0];
                output[0] = data[0];
                for (var i = 1, n = data.length; i < n; i++) {
                    output[i] = data[i] - data[i - 1];
                }
                output[0] = 0;
                return {
                    encodings: [{ kind: 'Delta', origin: origin, srcType: srcType }],
                    data: output
                };
            }
            Encoder.delta = delta;
            function isSigned(data) {
                for (var i = 0, n = data.length; i < n; i++) {
                    if (data[i] < 0)
                        return true;
                }
                return false;
            }
            function packingSize(data, upperLimit) {
                var lowerLimit = -upperLimit - 1;
                var size = 0;
                for (var i = 0, n = data.length; i < n; i++) {
                    var value = data[i];
                    if (value === 0) {
                        size += 1;
                    }
                    else if (value > 0) {
                        size += Math.ceil(value / upperLimit);
                        if (value % upperLimit === 0)
                            size += 1;
                    }
                    else {
                        size += Math.ceil(value / lowerLimit);
                        if (value % lowerLimit === 0)
                            size += 1;
                    }
                }
                return size;
            }
            function determinePacking(data) {
                var signed = isSigned(data);
                var size8 = signed ? packingSize(data, 0x7F) : packingSize(data, 0xFF);
                var size16 = signed ? packingSize(data, 0x7FFF) : packingSize(data, 0xFFFF);
                if (data.length * 4 < size16 * 2) {
                    // 4 byte packing is the most effective
                    return {
                        isSigned: signed,
                        size: data.length,
                        bytesPerElement: 4
                    };
                }
                else if (size16 * 2 < size8) {
                    // 2 byte packing is the most effective
                    return {
                        isSigned: signed,
                        size: size16,
                        bytesPerElement: 2
                    };
                }
                else {
                    // 1 byte packing is the most effective
                    return {
                        isSigned: signed,
                        size: size8,
                        bytesPerElement: 1
                    };
                }
                ;
            }
            function _integerPacking(data, packing) {
                var upperLimit = packing.isSigned
                    ? (packing.bytesPerElement === 1 ? 0x7F : 0x7FFF)
                    : (packing.bytesPerElement === 1 ? 0xFF : 0xFFFF);
                var lowerLimit = -upperLimit - 1;
                var n = data.length;
                var packed = packing.isSigned
                    ? packing.bytesPerElement === 1 ? new Int8Array(packing.size) : new Int16Array(packing.size)
                    : packing.bytesPerElement === 1 ? new Uint8Array(packing.size) : new Uint16Array(packing.size);
                var j = 0;
                for (var i = 0; i < n; i++) {
                    var value = data[i];
                    if (value >= 0) {
                        while (value >= upperLimit) {
                            packed[j] = upperLimit;
                            ++j;
                            value -= upperLimit;
                        }
                    }
                    else {
                        while (value <= lowerLimit) {
                            packed[j] = lowerLimit;
                            ++j;
                            value -= lowerLimit;
                        }
                    }
                    packed[j] = value;
                    ++j;
                }
                var result = byteArray(packed);
                return {
                    encodings: [{
                            kind: 'IntegerPacking',
                            byteCount: packing.bytesPerElement,
                            isUnsigned: !packing.isSigned,
                            srcSize: n
                        },
                        result.encodings[0]
                    ],
                    data: result.data
                };
            }
            /**
             * Packs Int32 array. The packing level is determined automatically to either 1-, 2-, or 4-byte words.
             */
            function integerPacking(data) {
                if (!(data instanceof Int32Array)) {
                    throw new Error('Integer packing can only be applied to Int32 data.');
                }
                var packing = determinePacking(data);
                if (packing.bytesPerElement === 4) {
                    // no packing done, Int32 encoding will be used
                    return byteArray(data);
                }
                return _integerPacking(data, packing);
            }
            Encoder.integerPacking = integerPacking;
            function stringArray(data) {
                var map = Object.create(null);
                var strings = [];
                var accLength = 0;
                var offsets = CIFTools.Utils.ChunkedArray.create(function (s) { return new Int32Array(s); }, 1024, 1);
                var output = new Int32Array(data.length);
                CIFTools.Utils.ChunkedArray.add(offsets, 0);
                var i = 0;
                for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
                    var s = data_1[_i];
                    // handle null strings.
                    if (s === null || s === void 0) {
                        output[i++] = -1;
                        continue;
                    }
                    var index = map[s];
                    if (index === void 0) {
                        // increment the length
                        accLength += s.length;
                        // store the string and index                   
                        index = strings.length;
                        strings[index] = s;
                        map[s] = index;
                        // write the offset
                        CIFTools.Utils.ChunkedArray.add(offsets, accLength);
                    }
                    output[i++] = index;
                }
                var encOffsets = Encoder.by(delta).and(integerPacking).encode(CIFTools.Utils.ChunkedArray.compact(offsets));
                var encOutput = Encoder.by(delta).and(runLength).and(integerPacking).encode(output);
                return {
                    encodings: [{ kind: 'StringArray', dataEncoding: encOutput.encoding, stringData: strings.join(''), offsetEncoding: encOffsets.encoding, offsets: encOffsets.data }],
                    data: encOutput.data
                };
            }
            Encoder.stringArray = stringArray;
            var _a, _b;
        })(Encoder = Binary.Encoder || (Binary.Encoder = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        Binary.VERSION = '0.3.0';
        var Encoding;
        (function (Encoding) {
            function getDataType(data) {
                var srcType;
                if (data instanceof Int8Array)
                    srcType = 1 /* Int8 */;
                else if (data instanceof Int16Array)
                    srcType = 2 /* Int16 */;
                else if (data instanceof Int32Array)
                    srcType = 3 /* Int32 */;
                else if (data instanceof Uint8Array)
                    srcType = 4 /* Uint8 */;
                else if (data instanceof Uint16Array)
                    srcType = 5 /* Uint16 */;
                else if (data instanceof Uint32Array)
                    srcType = 6 /* Uint32 */;
                else if (data instanceof Float32Array)
                    srcType = 32 /* Float32 */;
                else if (data instanceof Float64Array)
                    srcType = 33 /* Float64 */;
                else
                    throw new Error('Unsupported integer data type.');
                return srcType;
            }
            Encoding.getDataType = getDataType;
            function isSignedIntegerDataType(data) {
                return data instanceof Int8Array || data instanceof Int16Array || data instanceof Int32Array;
            }
            Encoding.isSignedIntegerDataType = isSignedIntegerDataType;
        })(Encoding = Binary.Encoding || (Binary.Encoding = {}));
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        function checkVersions(min, current) {
            for (var i = 0; i < 2; i++) {
                if (min[i] > current[i])
                    return false;
            }
            return true;
        }
        function parse(data) {
            var minVersion = [0, 3];
            try {
                var array = new Uint8Array(data);
                var unpacked = Binary.MessagePack.decode(array);
                if (!checkVersions(minVersion, unpacked.version.match(/(\d)\.(\d)\.\d/).slice(1))) {
                    return CIFTools.ParserResult.error("Unsupported format version. Current " + unpacked.version + ", required " + minVersion.join('.') + ".");
                }
                var file = new Binary.File(unpacked);
                return CIFTools.ParserResult.success(file);
            }
            catch (e) {
                return CIFTools.ParserResult.error('' + e);
            }
        }
        Binary.parse = parse;
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under MIT License, See LICENSE file for more info.
 */
var CIFTools;
(function (CIFTools) {
    var Binary;
    (function (Binary) {
        "use strict";
        function encodeField(field, data, totalCount) {
            var array, isNative = false;
            if (field.typedArray) {
                array = new field.typedArray(totalCount);
            }
            else {
                isNative = true;
                array = new Array(totalCount);
            }
            var mask = new Uint8Array(totalCount);
            var presence = field.presence;
            var getter = field.number ? field.number : field.string;
            var allPresent = true;
            var offset = 0;
            for (var _i = 0, data_2 = data; _i < data_2.length; _i++) {
                var _d = data_2[_i];
                var d = _d.data;
                for (var i = 0, _b = _d.count; i < _b; i++) {
                    var p = presence ? presence(d, i) : 0 /* Present */;
                    if (p !== 0 /* Present */) {
                        mask[offset] = p;
                        if (isNative)
                            array[offset] = null;
                        allPresent = false;
                    }
                    else {
                        mask[offset] = 0 /* Present */;
                        array[offset] = getter(d, i);
                    }
                    offset++;
                }
            }
            var encoder = field.encoder ? field.encoder : Binary.Encoder.by(Binary.Encoder.stringArray);
            var encoded = encoder.encode(array);
            var maskData = void 0;
            if (!allPresent) {
                var maskRLE = Binary.Encoder.by(Binary.Encoder.runLength).and(Binary.Encoder.byteArray).encode(mask);
                if (maskRLE.data.length < mask.length) {
                    maskData = maskRLE;
                }
                else {
                    maskData = Binary.Encoder.by(Binary.Encoder.byteArray).encode(mask);
                }
            }
            return {
                name: field.name,
                data: encoded,
                mask: maskData
            };
        }
        var Writer = (function () {
            function Writer(encoder) {
                this.dataBlocks = [];
                this.data = {
                    encoder: encoder,
                    version: Binary.VERSION,
                    dataBlocks: this.dataBlocks
                };
            }
            Writer.prototype.startDataBlock = function (header) {
                this.dataBlocks.push({
                    header: (header || '').replace(/[ \n\t]/g, '').toUpperCase(),
                    categories: []
                });
            };
            Writer.prototype.writeCategory = function (category, contexts) {
                if (!this.data) {
                    throw new Error('The writer contents have already been encoded, no more writing.');
                }
                if (!this.dataBlocks.length) {
                    throw new Error('No data block created.');
                }
                var src = !contexts || !contexts.length ? [category(void 0)] : contexts.map(function (c) { return category(c); });
                var categories = src.filter(function (c) { return c && c.count > 0; });
                if (!categories.length)
                    return;
                var count = categories.reduce(function (a, c) { return a + c.count; }, 0);
                if (!count)
                    return;
                var first = categories[0];
                var cat = { name: first.desc.name, columns: [], rowCount: count };
                var data = categories.map(function (c) { return ({ data: c.data, count: c.count }); });
                for (var _i = 0, _a = first.desc.fields; _i < _a.length; _i++) {
                    var f = _a[_i];
                    cat.columns.push(encodeField(f, data, count));
                }
                this.dataBlocks[this.dataBlocks.length - 1].categories.push(cat);
            };
            Writer.prototype.encode = function () {
                this.encodedData = Binary.MessagePack.encode(this.data);
                this.data = null;
                this.dataBlocks = null;
            };
            Writer.prototype.flush = function (stream) {
                stream.writeBinary(this.encodedData);
            };
            return Writer;
        }());
        Binary.Writer = Writer;
    })(Binary = CIFTools.Binary || (CIFTools.Binary = {}));
})(CIFTools || (CIFTools = {}));
var LiteMolCIFTools = CIFTools;
// File:src/Three.js

var LiteMolTHREE = (function () {

/**
 * @author mrdoob / http://mrdoob.com/
 */

var THREE = { REVISION: '71' };

// polyfills

if ( Math.sign === undefined ) {

	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign

	Math.sign = function ( x ) {

		return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x;

	};

}


// set the default log handlers
THREE.log = function() { console.log.apply( console, arguments ); }
THREE.warn = function() { console.warn.apply( console, arguments ); }
THREE.error = function() { console.error.apply( console, arguments ); }


// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button

THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };

// 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;
THREE.MinEquation = 103;
THREE.MaxEquation = 104;

// 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 = 300;

THREE.CubeReflectionMapping = 301;
THREE.CubeRefractionMapping = 302;

THREE.EquirectangularReflectionMapping = 303;
THREE.EquirectangularRefractionMapping = 304;

THREE.SphericalReflectionMapping = 305;

// 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;
THREE.HalfFloatType = 1025;

// 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;
// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders
THREE.RGBEFormat = THREE.RGBAFormat; //1024;

// DDS / ST3C 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;


// 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;


// DEPRECATED

THREE.Projector = function () {

	THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );

	this.projectVector = function ( vector, camera ) {

		THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
		vector.project( camera );

	};

	this.unprojectVector = function ( vector, camera ) {

		THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
		vector.unproject( camera );

	};

	this.pickingRay = function ( vector, camera ) {

		THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );

	};

};

THREE.CanvasRenderer = function () {

	THREE.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 () {};

};

// File:src/math/Color.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Color = function ( color ) {

	if ( arguments.length === 3 ) {

		return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] );

	}

	return this.set( color )

};

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, gammaFactor ) {

		if ( gammaFactor === undefined ) gammaFactor = 2.0;

		this.r = Math.pow( color.r, gammaFactor );
		this.g = Math.pow( color.g, gammaFactor );
		this.b = Math.pow( color.b, gammaFactor );

		return this;

	},

	copyLinearToGamma: function ( color, gammaFactor ) {

		if ( gammaFactor === undefined ) gammaFactor = 2.0;

		var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;

		this.r = Math.pow( color.r, safeInverse );
		this.g = Math.pow( color.g, safeInverse );
		this.b = Math.pow( color.b, safeInverse );

		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 ( optionalTarget ) {

		// h,s,l ranges are in 0.0 - 1.0

		var hsl = optionalTarget || { h: 0, s: 0, l: 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 );

	},

	fromArray: function ( array ) {

		this.r = array[ 0 ];
		this.g = array[ 1 ];
		this.b = array[ 2 ];

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this.r;
		array[ offset + 1 ] = this.g;
		array[ offset + 2 ] = this.b;

		return array;
	},

	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 };

// File:src/math/Quaternion.js

/**
 * @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,

	_x: 0,_y: 0, _z: 0, _w: 0,

	get x () {

		return this._x;

	},

	set x ( value ) {

		this._x = value;
		this.onChangeCallback();

	},

	get y () {

		return this._y;

	},

	set y ( value ) {

		this._y = value;
		this.onChangeCallback();

	},

	get z () {

		return this._z;

	},

	set z ( value ) {

		this._z = value;
		this.onChangeCallback();

	},

	get w () {

		return this._w;

	},

	set w ( value ) {

		this._w = value;
		this.onChangeCallback();

	},

	set: function ( x, y, z, w ) {

		this._x = x;
		this._y = y;
		this._z = z;
		this._w = w;

		this.onChangeCallback();

		return this;

	},

	copy: function ( quaternion ) {

		this._x = quaternion.x;
		this._y = quaternion.y;
		this._z = quaternion.z;
		this._w = quaternion.w;

		this.onChangeCallback();

		return this;

	},

	setFromEuler: function ( euler, update ) {

		if ( euler instanceof THREE.Euler === false ) {

			throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and 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( euler._x / 2 );
		var c2 = Math.cos( euler._y / 2 );
		var c3 = Math.cos( euler._z / 2 );
		var s1 = Math.sin( euler._x / 2 );
		var s2 = Math.sin( euler._y / 2 );
		var s3 = Math.sin( euler._z / 2 );

		if ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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;

		}

		if ( update !== false ) this.onChangeCallback();

		return this;

	},

	setFromAxisAngle: function ( axis, angle ) {

		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm

		// assumes axis is 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 );

		this.onChangeCallback();

		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;

		}

		this.onChangeCallback();

		return this;

	},

	setFromUnitVectors: function () {

		// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final

		// assumes direction vectors vFrom and vTo are normalized

		var v1, r;

		var EPS = 0.000001;

		return function ( vFrom, vTo ) {

			if ( v1 === undefined ) v1 = new THREE.Vector3();

			r = vFrom.dot( vTo ) + 1;

			if ( r < EPS ) {

				r = 0;

				if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {

					v1.set( - vFrom.y, vFrom.x, 0 );

				} else {

					v1.set( 0, - vFrom.z, vFrom.y );

				}

			} else {

				v1.crossVectors( vFrom, vTo );

			}

			this._x = v1.x;
			this._y = v1.y;
			this._z = v1.z;
			this._w = r;

			this.normalize();

			return this;

		}

	}(),

	inverse: function () {

		this.conjugate().normalize();

		return this;

	},

	conjugate: function () {

		this._x *= - 1;
		this._y *= - 1;
		this._z *= - 1;

		this.onChangeCallback();

		return this;

	},

	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 );

	},

	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;

		}

		this.onChangeCallback();

		return this;

	},

	multiply: function ( q, p ) {

		if ( p !== undefined ) {

			THREE.warn( 'THREE.Quaternion: .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;

		this.onChangeCallback();

		return this;

	},

	multiplyVector3: function ( vector ) {

		THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
		return vector.applyQuaternion( this );

	},

	slerp: function ( qb, t ) {

		if ( t === 0 ) return this;
		if ( t === 1 ) return this.copy( qb );

		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 );

		this.onChangeCallback();

		return this;

	},

	equals: function ( quaternion ) {

		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );

	},

	fromArray: function ( array, offset ) {

		if ( offset === undefined ) offset = 0;

		this._x = array[ offset ];
		this._y = array[ offset + 1 ];
		this._z = array[ offset + 2 ];
		this._w = array[ offset + 3 ];

		this.onChangeCallback();

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this._x;
		array[ offset + 1 ] = this._y;
		array[ offset + 2 ] = this._z;
		array[ offset + 3 ] = this._w;

		return array;

	},

	onChange: function ( callback ) {

		this.onChangeCallback = callback;

		return this;

	},

	onChangeCallback: function () {},

	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 );

}

// File:src/math/Vector2.js

/**
 * @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 ) {

			THREE.warn( 'THREE.Vector2: .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;

	},

	addScalar: function ( s ) {

		this.x += s;
		this.y += s;

		return this;

	},

	addVectors: function ( a, b ) {

		this.x = a.x + b.x;
		this.y = a.y + b.y;

		return this;

	},

	sub: function ( v, w ) {

		if ( w !== undefined ) {

			THREE.warn( 'THREE.Vector2: .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;

	},

	subScalar: function ( s ) {

		this.x -= s;
		this.y -= s;

		return this;

	},

	subVectors: function ( a, b ) {

		this.x = a.x - b.x;
		this.y = a.y - b.y;

		return this;

	},

	multiply: function ( v ) {

		this.x *= v.x;
		this.y *= v.y;

		return this;

	},

	multiplyScalar: function ( s ) {

		this.x *= s;
		this.y *= s;

		return this;

	},

	divide: function ( v ) {

		this.x /= v.x;
		this.y /= v.y;

		return this;

	},

	divideScalar: function ( scalar ) {

		if ( scalar !== 0 ) {

			var invScalar = 1 / scalar;

			this.x *= invScalar;
			this.y *= invScalar;

		} else {

			this.x = 0;
			this.y = 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;
	},

	clampScalar: ( function () {

		var min, max;

		return function ( minVal, maxVal ) {

			if ( min === undefined ) {

				min = new THREE.Vector2();
				max = new THREE.Vector2();

			}

			min.set( minVal, minVal );
			max.set( maxVal, maxVal );

			return this.clamp( min, max );

		};

	} )(),

	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 = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );

		return this;

	},

	negate: function () {

		this.x = - this.x;
		this.y = - this.y;

		return this;

	},

	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;

	},

	lerpVectors: function ( v1, v2, alpha ) {

		this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		return this;

	},

	equals: function ( v ) {

		return ( ( v.x === this.x ) && ( v.y === this.y ) );

	},

	fromArray: function ( array, offset ) {

		if ( offset === undefined ) offset = 0;

		this.x = array[ offset ];
		this.y = array[ offset + 1 ];

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this.x;
		array[ offset + 1 ] = this.y;

		return array;

	},

	fromAttribute: function ( attribute, index, offset ) {

		if ( offset === undefined ) offset = 0;

		index = index * attribute.itemSize + offset;

		this.x = attribute.array[ index ];
		this.y = attribute.array[ index + 1 ];

		return this;

	},

	clone: function () {

		return new THREE.Vector2( this.x, this.y );

	}

};

// File:src/math/Vector3.js

/**
 * @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 ) {

			THREE.warn( 'THREE.Vector3: .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 ) {

			THREE.warn( 'THREE.Vector3: .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;

	},
	
	subScalar: function ( s ) {

		this.x -= s;
		this.y -= s;
		this.z -= s;

		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 ) {

			THREE.warn( 'THREE.Vector3: .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 ( scalar ) {

		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;

		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 quaternion;

		return function ( euler ) {

			if ( euler instanceof THREE.Euler === false ) {

				THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' );

			}

			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();

			this.applyQuaternion( quaternion.setFromEuler( euler ) );

			return this;

		};

	}(),

	applyAxisAngle: function () {

		var quaternion;

		return function ( axis, angle ) {

			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();

			this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );

			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;

	},

	project: function () {

		var matrix;

		return function ( camera ) {

			if ( matrix === undefined ) matrix = new THREE.Matrix4();

			matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
			return this.applyProjection( matrix );

		};

	}(),

	unproject: function () {

		var matrix;

		return function ( camera ) {

			if ( matrix === undefined ) matrix = new THREE.Matrix4();

			matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
			return this.applyProjection( matrix );

		};

	}(),

	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 ( scalar ) {

		if ( scalar !== 0 ) {

			var invScalar = 1 / scalar;

			this.x *= invScalar;
			this.y *= invScalar;
			this.z *= invScalar;

		} 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;

	},

	clampScalar: ( function () {

		var min, max;

		return function ( minVal, maxVal ) {

			if ( min === undefined ) {

				min = new THREE.Vector3();
				max = new THREE.Vector3();

			}

			min.set( minVal, minVal, minVal );
			max.set( maxVal, maxVal, maxVal );

			return this.clamp( min, max );

		};

	} )(),

	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 );

		return this;

	},

	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 = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
		this.z = ( this.z < 0 ) ? 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 ( 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;

	},

	lerpVectors: function ( v1, v2, alpha ) {

		this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		return this;

	},

	cross: function ( v, w ) {

		if ( w !== undefined ) {

			THREE.warn( 'THREE.Vector3: .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 ) {

		var ax = a.x, ay = a.y, az = a.z;
		var bx = b.x, by = b.y, bz = b.z;

		this.x = ay * bz - az * by;
		this.y = az * bx - ax * bz;
		this.z = ax * by - ay * bx;

		return this;

	},

	projectOnVector: function () {

		var v1, dot;

		return function ( vector ) {

			if ( v1 === undefined ) v1 = new THREE.Vector3();

			v1.copy( vector ).normalize();

			dot = this.dot( v1 );

			return this.copy( v1 ).multiplyScalar( dot );

		};

	}(),

	projectOnPlane: function () {

		var v1;

		return function ( planeNormal ) {

			if ( v1 === undefined ) v1 = new THREE.Vector3();

			v1.copy( this ).projectOnVector( planeNormal );

			return this.sub( v1 );

		}

	}(),

	reflect: function () {

		// reflect incident vector off plane orthogonal to normal
		// normal is assumed to have unit length

		var v1;

		return function ( normal ) {

			if ( v1 === undefined ) v1 = new THREE.Vector3();

			return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );

		}

	}(),

	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 ) {

		THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );

	},

	setEulerFromQuaternion: function ( q, order ) {

		THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );

	},

	getPositionFromMatrix: function ( m ) {

		THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );

		return this.setFromMatrixPosition( m );

	},

	getScaleFromMatrix: function ( m ) {

		THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );

		return this.setFromMatrixScale( m );
	},

	getColumnFromMatrix: function ( index, matrix ) {

		THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );

		return this.setFromMatrixColumn( index, matrix );

	},

	setFromMatrixPosition: function ( m ) {

		this.x = m.elements[ 12 ];
		this.y = m.elements[ 13 ];
		this.z = m.elements[ 14 ];

		return this;

	},

	setFromMatrixScale: 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;
	},

	setFromMatrixColumn: 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, offset ) {

		if ( offset === undefined ) offset = 0;

		this.x = array[ offset ];
		this.y = array[ offset + 1 ];
		this.z = array[ offset + 2 ];

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this.x;
		array[ offset + 1 ] = this.y;
		array[ offset + 2 ] = this.z;

		return array;

	},

	fromAttribute: function ( attribute, index, offset ) {

		if ( offset === undefined ) offset = 0;

		index = index * attribute.itemSize + offset;

		this.x = attribute.array[ index ];
		this.y = attribute.array[ index + 1 ];
		this.z = attribute.array[ index + 2 ];

		return this;

	},

	clone: function () {

		return new THREE.Vector3( this.x, this.y, this.z );

	}

};

// File:src/math/Vector4.js

/**
 * @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 ) {

			THREE.warn( 'THREE.Vector4: .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 ) {

			THREE.warn( 'THREE.Vector4: .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;

	},

	subScalar: function ( s ) {

		this.x -= s;
		this.y -= s;
		this.z -= s;
		this.w -= s;

		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 ( scalar ) {

		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;
		this.w *= scalar;

		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 ( scalar ) {

		if ( scalar !== 0 ) {

			var invScalar = 1 / scalar;

			this.x *= invScalar;
			this.y *= invScalar;
			this.z *= invScalar;
			this.w *= invScalar;

		} 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;

	},

	clampScalar: ( function () {

		var min, max;

		return function ( minVal, maxVal ) {

			if ( min === undefined ) {

				min = new THREE.Vector4();
				max = new THREE.Vector4();

			}

			min.set( minVal, minVal, minVal, minVal );
			max.set( maxVal, maxVal, maxVal, maxVal );

			return this.clamp( min, max );

		};

	} )(),

  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( this.w );

		return this;

  },

  roundToZero: function () {

		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
		this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
		this.w = ( this.w < 0 ) ? 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 ( 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;

	},

	lerpVectors: function ( v1, v2, alpha ) {

		this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		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, offset ) {

		if ( offset === undefined ) offset = 0;

		this.x = array[ offset ];
		this.y = array[ offset + 1 ];
		this.z = array[ offset + 2 ];
		this.w = array[ offset + 3 ];

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this.x;
		array[ offset + 1 ] = this.y;
		array[ offset + 2 ] = this.z;
		array[ offset + 3 ] = this.w;

		return array;

	},

	fromAttribute: function ( attribute, index, offset ) {

		if ( offset === undefined ) offset = 0;

		index = index * attribute.itemSize + offset;

		this.x = attribute.array[ index ];
		this.y = attribute.array[ index + 1 ];
		this.z = attribute.array[ index + 2 ];
		this.w = attribute.array[ index + 3 ];

		return this;

	},

	clone: function () {

		return new THREE.Vector4( this.x, this.y, this.z, this.w );

	}

};

// File:src/math/Euler.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://exocortex.com
 */

THREE.Euler = function ( x, y, z, order ) {

	this._x = x || 0;
	this._y = y || 0;
	this._z = z || 0;
	this._order = order || THREE.Euler.DefaultOrder;

};

THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];

THREE.Euler.DefaultOrder = 'XYZ';

THREE.Euler.prototype = {

	constructor: THREE.Euler,

	_x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder,

	get x () {

		return this._x;

	},

	set x ( value ) {

		this._x = value;
		this.onChangeCallback();

	},

	get y () {

		return this._y;

	},

	set y ( value ) {

		this._y = value;
		this.onChangeCallback();

	},

	get z () {

		return this._z;

	},

	set z ( value ) {

		this._z = value;
		this.onChangeCallback();

	},

	get order () {

		return this._order;

	},

	set order ( value ) {

		this._order = value;
		this.onChangeCallback();

	},

	set: function ( x, y, z, order ) {

		this._x = x;
		this._y = y;
		this._z = z;
		this._order = order || this._order;

		this.onChangeCallback();

		return this;

	},

	copy: function ( euler ) {

		this._x = euler._x;
		this._y = euler._y;
		this._z = euler._z;
		this._order = euler._order;

		this.onChangeCallback();

		return this;

	},

	setFromRotationMatrix: function ( m, order, update ) {

		var clamp = THREE.Math.clamp;

		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

		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 ];

		order = order || this._order;

		if ( order === 'XYZ' ) {

			this._y = Math.asin( clamp( m13, - 1, 1 ) );

			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, - 1, 1 ) );

			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, - 1, 1 ) );

			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, - 1, 1 ) );

			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, - 1, 1 ) );

			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, - 1, 1 ) );

			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;

			}

		} else {

			THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order )

		}

		this._order = order;

		if ( update !== false ) this.onChangeCallback();

		return this;

	},

	setFromQuaternion: function () {

		var matrix;

		return function ( q, order, update ) {

			if ( matrix === undefined ) matrix = new THREE.Matrix4();
			matrix.makeRotationFromQuaternion( q );
			this.setFromRotationMatrix( matrix, order, update );

			return this;

		};

	}(),

	setFromVector3: function ( v, order ) {

		return this.set( v.x, v.y, v.z, order || this._order );

	},

	reorder: function () {

		// WARNING: this discards revolution information -bhouston

		var q = new THREE.Quaternion();

		return function ( newOrder ) {

			q.setFromEuler( this );
			this.setFromQuaternion( q, newOrder );

		};

	}(),

	equals: function ( euler ) {

		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );

	},

	fromArray: function ( array ) {

		this._x = array[ 0 ];
		this._y = array[ 1 ];
		this._z = array[ 2 ];
		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];

		this.onChangeCallback();

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		array[ offset ] = this._x;
		array[ offset + 1 ] = this._y;
		array[ offset + 2 ] = this._z;
		array[ offset + 3 ] = this._order;

		return array;
	},

	toVector3: function ( optionalResult ) {

		if ( optionalResult ) {

			return optionalResult.set( this._x, this._y, this._z );

		} else {

			return new THREE.Vector3( this._x, this._y, this._z );

		}

	},

	onChange: function ( callback ) {

		this.onChangeCallback = callback;

		return this;

	},

	onChangeCallback: function () {},

	clone: function () {

		return new THREE.Euler( this._x, this._y, this._z, this._order );

	}

};

// File:src/math/Line3.js

/**
 * @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 );

	}

};

// File:src/math/Box2.js

/**
 * @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 ) {

		this.makeEmpty();

		for ( var i = 0, il = points.length; i < il; i ++ ) {

			this.expandByPoint( points[ i ] )

		}

		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, optionalTarget ) {

		// This can potentially have a divide by zero if the box
		// has a size dimension of 0.

		var result = optionalTarget || new THREE.Vector2();

		return result.set(
			( 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 );

	}

};

// File:src/math/Box3.js

/**
 * @author bhouston / http://exocortex.com
 * @author WestLangley / http://github.com/WestLangley
 */

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 ) {

		this.makeEmpty();

		for ( var i = 0, il = points.length; i < il; i ++ ) {

			this.expandByPoint( points[ i ] )

		}

		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;

		};

	}(),

	setFromObject: function () {

		// Computes the world-axis-aligned bounding box of an object (including its children),
		// accounting for both the object's, and childrens', world transforms

		var v1 = new THREE.Vector3();

		return function ( object ) {

			var scope = this;

			object.updateMatrixWorld( true );

			this.makeEmpty();

			object.traverse( function ( node ) {

				var geometry = node.geometry;

				if ( geometry !== undefined ) {

					if ( geometry instanceof THREE.Geometry ) {

						var vertices = geometry.vertices;

						for ( var i = 0, il = vertices.length; i < il; i ++ ) {

							v1.copy( vertices[ i ] );

							v1.applyMatrix4( node.matrixWorld );

							scope.expandByPoint( v1 );

						}

					} else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) {

						var positions = geometry.attributes[ 'position' ].array;

						for ( var i = 0, il = positions.length; i < il; i += 3 ) {

							v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );

							v1.applyMatrix4( node.matrixWorld );

							scope.expandByPoint( v1 );

						}

					}

				}

			} );

			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, optionalTarget ) {

		// This can potentially have a divide by zero if the box
		// has a size dimension of 0.

		var result = optionalTarget || new THREE.Vector3();

		return result.set(
			( 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 );

	}

};

// File:src/math/Matrix3.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://exocortex.com
 */

THREE.Matrix3 = function () {

	this.elements = new Float32Array( [

		1, 0, 0,
		0, 1, 0,
		0, 0, 1

	] );

	if ( arguments.length > 0 ) {

		THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );

	}

};

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 ) {

		THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
		return vector.applyMatrix3( this );

	},

	multiplyVector3Array: function ( a ) {

		THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );
		return this.applyToVector3Array( a );

	},

	applyToVector3Array: function () {

		var v1 = new THREE.Vector3();

		return function ( array, offset, length ) {

			if ( offset === undefined ) offset = 0;
			if ( length === undefined ) length = array.length;

			for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {

				v1.x = array[ j ];
				v1.y = array[ j + 1 ];
				v1.z = array[ j + 2 ];

				v1.applyMatrix3( this );

				array[ j ]     = v1.x;
				array[ j + 1 ] = v1.y;
				array[ j + 2 ] = v1.z;

			}

			return array;

		};

	}(),

	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 {

				THREE.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;

	},

	flattenToArrayOffset: function ( array, offset ) {

		var te = this.elements;

		array[ offset     ] = te[ 0 ];
		array[ offset + 1 ] = te[ 1 ];
		array[ offset + 2 ] = te[ 2 ];

		array[ offset + 3 ] = te[ 3 ];
		array[ offset + 4 ] = te[ 4 ];
		array[ offset + 5 ] = te[ 5 ];

		array[ offset + 6 ] = te[ 6 ];
		array[ offset + 7 ] = te[ 7 ];
		array[ offset + 8 ]  = te[ 8 ];

		return array;

	},

	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;

	},

	fromArray: function ( array ) {

		this.elements.set( array );

		return this;

	},

	toArray: function () {

		var te = this.elements;

		return [
			te[ 0 ], te[ 1 ], te[ 2 ],
			te[ 3 ], te[ 4 ], te[ 5 ],
			te[ 6 ], te[ 7 ], te[ 8 ]
		];

	},

	clone: function () {

		return new THREE.Matrix3().fromArray( this.elements );

	}

};

// File:src/math/Matrix4.js

/**
 * @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 () {

	this.elements = new Float32Array( [

		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1

	] );

	if ( arguments.length > 0 ) {

		THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );

	}

};

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 ) {

		this.elements.set( m.elements );

		return this;

	},

	extractPosition: function ( m ) {

		THREE.warn( 'THREE.Matrix4: .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;

	},

	extractBasis: function ( xAxis, yAxis, zAxis ) {
 
		var te = this.elements;
 
		xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] );
		yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] );
		zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] );
 
		return this;
 		
	},
 
	makeBasis: function ( xAxis, yAxis, zAxis ) {

		this.set(
			xAxis.x, yAxis.x, zAxis.x, 0,
			xAxis.y, yAxis.y, zAxis.y, 0,
			xAxis.z, yAxis.z, zAxis.z, 0,
			0,       0,       0,       1
		);

		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;

		};

	}(),

	makeRotationFromEuler: function ( euler ) {

		if ( euler instanceof THREE.Euler === false ) {

			THREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );

		}

		var te = this.elements;

		var x = euler.x, y = euler.y, z = euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ) {

		THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );

		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 ) {

			THREE.warn( 'THREE.Matrix4: .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 ) {

		THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' );
		return vector.applyProjection( this );

	},

	multiplyVector4: function ( vector ) {

		THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
		return vector.applyMatrix4( this );

	},

	multiplyVector3Array: function ( a ) {

		THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );
		return this.applyToVector3Array( a );

	},

	applyToVector3Array: function () {

		var v1 = new THREE.Vector3();

		return function ( array, offset, length ) {

			if ( offset === undefined ) offset = 0;
			if ( length === undefined ) length = array.length;

			for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {

				v1.x = array[ j ];
				v1.y = array[ j + 1 ];
				v1.z = array[ j + 2 ];

				v1.applyMatrix4( this );

				array[ j ]     = v1.x;
				array[ j + 1 ] = v1.y;
				array[ j + 2 ] = v1.z;

			}

			return array;

		};

	}(),

	rotateAxis: function ( v ) {

		THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );

		v.transformDirection( this );

	},

	crossVector: function ( vector ) {

		THREE.warn( 'THREE.Matrix4: .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;

	},

	flattenToArrayOffset: function ( array, offset ) {

		var te = this.elements;

		array[ offset     ] = te[ 0 ];
		array[ offset + 1 ] = te[ 1 ];
		array[ offset + 2 ] = te[ 2 ];
		array[ offset + 3 ] = te[ 3 ];

		array[ offset + 4 ] = te[ 4 ];
		array[ offset + 5 ] = te[ 5 ];
		array[ offset + 6 ] = te[ 6 ];
		array[ offset + 7 ] = te[ 7 ];

		array[ offset + 8 ]  = te[ 8 ];
		array[ offset + 9 ]  = te[ 9 ];
		array[ offset + 10 ] = te[ 10 ];
		array[ offset + 11 ] = te[ 11 ];

		array[ offset + 12 ] = te[ 12 ];
		array[ offset + 13 ] = te[ 13 ];
		array[ offset + 14 ] = te[ 14 ];
		array[ offset + 15 ] = te[ 15 ];

		return array;

	},

	getPosition: function () {

		var v1 = new THREE.Vector3();

		return function () {

			THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( 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 = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ];

		if ( det == 0 ) {

			var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";

			if ( throwOnInvertible || false ) {

				throw new Error( msg );

			} else {

				THREE.warn( msg );

			}

			this.identity();

			return this;
		}

		this.multiplyScalar( 1 / det );

		return this;

	},

	translate: function ( v ) {

		THREE.error( 'THREE.Matrix4: .translate() has been removed.' );

	},

	rotateX: function ( angle ) {

		THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' );

	},

	rotateY: function ( angle ) {

		THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' );

	},

	rotateZ: function ( angle ) {

		THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' );

	},

	rotateByAxis: function ( axis, angle ) {

		THREE.error( 'THREE.Matrix4: .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 ) {

		this.makeRotationFromQuaternion( quaternion );
		this.scale( scale );
		this.setPosition( position );

		return this;

	},

	decompose: function () {

		var vector = new THREE.Vector3();
		var matrix = new THREE.Matrix4();

		return function ( position, quaternion, scale ) {

			var te = this.elements;

			var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
			var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
			var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();

			// if determine is negative, we need to invert one scale
			var det = this.determinant();
			if ( det < 0 ) {
				sx = - sx;
			}

			position.x = te[ 12 ];
			position.y = te[ 13 ];
			position.z = te[ 14 ];

			// scale the rotation part

			matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()

			var invSX = 1 / sx;
			var invSY = 1 / sy;
			var invSZ = 1 / sz;

			matrix.elements[ 0 ] *= invSX;
			matrix.elements[ 1 ] *= invSX;
			matrix.elements[ 2 ] *= invSX;

			matrix.elements[ 4 ] *= invSY;
			matrix.elements[ 5 ] *= invSY;
			matrix.elements[ 6 ] *= invSY;

			matrix.elements[ 8 ] *= invSZ;
			matrix.elements[ 9 ] *= invSZ;
			matrix.elements[ 10 ] *= invSZ;

			quaternion.setFromRotationMatrix( matrix );

			scale.x = sx;
			scale.y = sy;
			scale.z = sz;

			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;

	},

	fromArray: function ( array ) {

		this.elements.set( array );

		return this;

	},

	toArray: function () {

		var te = this.elements;

		return [
			te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ],
			te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ],
			te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ],
			te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ]
		];

	},

	clone: function () {

		return new THREE.Matrix4().fromArray( this.elements );

	}

};

// File:src/math/Ray.js

/**
 * @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 );

		if ( directionDistance < 0 ) {

			return result.copy( this.origin );

		}

		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 );

			// point behind the ray

			if ( directionDistance < 0 ) {

				return this.origin.distanceTo( point );

			}

			v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );

			return v1.distanceTo( point );

		};

	}(),

	distanceSqToSegment: function () {

		var segCenter = new THREE.Vector3();
		var segDir = new THREE.Vector3();
		var diff = new THREE.Vector3();

		return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

			// from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp
			// It returns the min distance between the ray and the segment
			// defined by v0 and v1
			// It can also set two optional targets :
			// - The closest point on the ray
			// - The closest point on the segment

			segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
			segDir.copy( v1 ).sub( v0 ).normalize();
			diff.copy( this.origin ).sub( segCenter );

			var segExtent = v0.distanceTo( v1 ) * 0.5;
			var a01 = - this.direction.dot( segDir );
			var b0 = diff.dot( this.direction );
			var b1 = - diff.dot( segDir );
			var c = diff.lengthSq();
			var det = Math.abs( 1 - a01 * a01 );
			var s0, s1, sqrDist, extDet;

			if ( det > 0 ) {

				// The ray and segment are not parallel.

				s0 = a01 * b1 - b0;
				s1 = a01 * b0 - b1;
				extDet = segExtent * det;

				if ( s0 >= 0 ) {

					if ( s1 >= - extDet ) {

						if ( s1 <= extDet ) {

							// region 0
							// Minimum at interior points of ray and segment.

							var invDet = 1 / det;
							s0 *= invDet;
							s1 *= invDet;
							sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;

						} else {

							// region 1

							s1 = segExtent;
							s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

						}

					} else {

						// region 5

						s1 = - segExtent;
						s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

					}

				} else {

					if ( s1 <= - extDet ) {

						// region 4

						s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
						s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

					} else if ( s1 <= extDet ) {

						// region 3

						s0 = 0;
						s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
						sqrDist = s1 * ( s1 + 2 * b1 ) + c;

					} else {

						// region 2

						s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
						s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

					}

				}

			} else {

				// Ray and segment are parallel.

				s1 = ( a01 > 0 ) ? - segExtent : segExtent;
				s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
				sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

			}

			if ( optionalPointOnRay ) {

				optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );

			}

			if ( optionalPointOnSegment ) {

				optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );

			}

			return sqrDist;

		};

	}(),


	isIntersectionSphere: function ( sphere ) {

		return this.distanceToPoint( sphere.center ) <= sphere.radius;

	},

	intersectSphere: function () {

		// from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/

		var v1 = new THREE.Vector3();

		return function ( sphere, optionalTarget ) {

			v1.subVectors( sphere.center, this.origin );

			var tca = v1.dot( this.direction );

			var d2 = v1.dot( v1 ) - tca * tca;

			var radius2 = sphere.radius * sphere.radius;

			if ( d2 > radius2 ) return null;

			var thc = Math.sqrt( radius2 - d2 );

			// t0 = first intersect point - entrance on front of sphere
			var t0 = tca - thc;

			// t1 = second intersect point - exit point on back of sphere
			var t1 = tca + thc;

			// test to see if both t0 and t1 are behind the ray - if so, return null
			if ( t0 < 0 && t1 < 0 ) return null;

			// test to see if t0 is behind the ray:
			// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
			// in order to always return an intersect point that is in front of the ray.
			if ( t0 < 0 ) return this.at( t1, optionalTarget );

			// else t0 is in front of the ray, so return the first collision point scaled by t0 
			return this.at( t0, optionalTarget );

		}

	}(),

	isIntersectionPlane: function ( plane ) {

		// check if the ray lies on the plane first

		var distToPoint = plane.distanceToPoint( this.origin );

		if ( distToPoint === 0 ) {

			return true;

		}

		var denominator = plane.normal.dot( this.direction );

		if ( denominator * distToPoint < 0 ) {

			return true;

		}

		// ray origin is behind the plane (and is pointing behind it)

		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;

			}

			// Null is preferable to undefined since undefined means.... it is undefined

			return null;

		}

		var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;

		// Return if the ray never intersects the plane

		return t >= 0 ? t :  null;

	},

	intersectPlane: function ( plane, optionalTarget ) {

		var t = this.distanceToPlane( plane );

		if ( t === null ) {

			return null;
		}

		return this.at( t, optionalTarget );

	},

	isIntersectionBox: function () {

		var v = new THREE.Vector3();

		return function ( box ) {

			return this.intersectBox( box, v ) !== null;

		};

	}(),

	intersectBox: function ( box, optionalTarget ) {

		// http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/

		var tmin,tmax,tymin,tymax,tzmin,tzmax;

		var invdirx = 1 / this.direction.x,
			invdiry = 1 / this.direction.y,
			invdirz = 1 / this.direction.z;

		var origin = this.origin;

		if ( invdirx >= 0 ) {

			tmin = ( box.min.x - origin.x ) * invdirx;
			tmax = ( box.max.x - origin.x ) * invdirx;

		} else {

			tmin = ( box.max.x - origin.x ) * invdirx;
			tmax = ( box.min.x - origin.x ) * invdirx;
		}

		if ( invdiry >= 0 ) {

			tymin = ( box.min.y - origin.y ) * invdiry;
			tymax = ( box.max.y - origin.y ) * invdiry;

		} else {

			tymin = ( box.max.y - origin.y ) * invdiry;
			tymax = ( box.min.y - origin.y ) * invdiry;
		}

		if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;

		// These lines also handle the case where tmin or tmax is NaN
		// (result of 0 * Infinity). x !== x returns true if x is NaN

		if ( tymin > tmin || tmin !== tmin ) tmin = tymin;

		if ( tymax < tmax || tmax !== tmax ) tmax = tymax;

		if ( invdirz >= 0 ) {

			tzmin = ( box.min.z - origin.z ) * invdirz;
			tzmax = ( box.max.z - origin.z ) * invdirz;

		} else {

			tzmin = ( box.max.z - origin.z ) * invdirz;
			tzmax = ( box.min.z - origin.z ) * invdirz;
		}

		if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;

		if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;

		if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;

		//return point closest to the ray (positive side)

		if ( tmax < 0 ) return null;

		return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );

	},

	intersectTriangle: function () {

		// Compute the offset origin, edges, and normal.
		var diff = new THREE.Vector3();
		var edge1 = new THREE.Vector3();
		var edge2 = new THREE.Vector3();
		var normal = new THREE.Vector3();

		return function ( a, b, c, backfaceCulling, optionalTarget ) {

			// from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp

			edge1.subVectors( b, a );
			edge2.subVectors( c, a );
			normal.crossVectors( edge1, edge2 );

			// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
			// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
			//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
			//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
			//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
			var DdN = this.direction.dot( normal );
			var sign;

			if ( DdN > 0 ) {

				if ( backfaceCulling ) return null;
				sign = 1;

			} else if ( DdN < 0 ) {

				sign = - 1;
				DdN = - DdN;

			} else {

				return null;

			}

			diff.subVectors( this.origin, a );
			var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );

			// b1 < 0, no intersection
			if ( DdQxE2 < 0 ) {

				return null;

			}

			var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );

			// b2 < 0, no intersection
			if ( DdE1xQ < 0 ) {

				return null;

			}

			// b1+b2 > 1, no intersection
			if ( DdQxE2 + DdE1xQ > DdN ) {

				return null;

			}

			// Line intersects triangle, check if ray does.
			var QdN = - sign * diff.dot( normal );

			// t < 0, no intersection
			if ( QdN < 0 ) {

				return null;

			}

			// Ray intersects triangle.
			return this.at( QdN / DdN, optionalTarget );

		};

	}(),

	applyMatrix4: function ( matrix4 ) {

		this.direction.add( this.origin ).applyMatrix4( matrix4 );
		this.origin.applyMatrix4( matrix4 );
		this.direction.sub( this.origin );
		this.direction.normalize();

		return this;
	},

	equals: function ( ray ) {

		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

	},

	clone: function () {

		return new THREE.Ray().copy( this );

	}

};

// File:src/math/Sphere.js

/**
 * @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;
	},

	setFromPoints: function () {

		var box = new THREE.Box3();

		return function ( points, optionalCenter ) {

			var center = this.center;

			if ( optionalCenter !== undefined ) {

				center.copy( optionalCenter );

			} else {

				box.setFromPoints( points ).center( center );

			}

			var maxRadiusSq = 0;

			for ( var i = 0, il = points.length; i < il; i ++ ) {

				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );

			}

			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 );

	}

};

// File:src/math/Frustum.js

/**
 * @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 sphere = new THREE.Sphere();

		return function ( object ) {

			var geometry = object.geometry;

			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

			sphere.copy( geometry.boundingSphere );
			sphere.applyMatrix4( object.matrixWorld );

			return this.intersectsSphere( sphere );

		};

	}(),

	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;

	},

	intersectsBox: function () {

		var p1 = new THREE.Vector3(),
			p2 = new THREE.Vector3();

		return function ( box ) {

			var planes = this.planes;

			for ( var i = 0; i < 6 ; i ++ ) {

				var plane = planes[ i ];

				p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
				p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
				p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
				p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
				p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
				p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;

				var d1 = plane.distanceToPoint( p1 );
				var d2 = plane.distanceToPoint( p2 );

				// if both outside plane, no intersection

				if ( d1 < 0 && d2 < 0 ) {

					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 );

	}

};

// File:src/math/Plane.js

/**
 * @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();
		var m1 = new THREE.Matrix3();

		return function ( matrix, optionalNormalMatrix ) {

			// compute new normal based on theory here:
			// http://www.songho.ca/opengl/gl_normaltransform.html
			var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
			var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix );

			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 );

	}

};

// File:src/math/Math.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Math = {

	generateUUID: function () {

		// http://www.broofa.com/Tools/Math.uuid.htm

		var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
		var uuid = new Array( 36 );
		var rnd = 0, r;

		return function () {

			for ( var i = 0; i < 36; i ++ ) {

				if ( i == 8 || i == 13 || i == 18 || i == 23 ) {

					uuid[ i ] = '-';

				} else if ( i == 14 ) {

					uuid[ i ] = '4';

				} else {

					if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
					r = rnd & 0xf;
					rnd = rnd >> 4;
					uuid[ i ] = chars[ ( i == 19 ) ? ( r & 0x3 ) | 0x8 : r ];

				}
			}

			return uuid.join( '' );

		};

	}(),

	// 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 Math.floor( this.randFloat( low, high ) );

	},

	// 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() );

	},

	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;

		};

	}(),

	isPowerOfTwo: function ( value ) {

		return ( value & ( value - 1 ) ) === 0 && value !== 0;

	},

	nextPowerOfTwo: function ( value ) {

		value --;
		value |= value >> 1;
		value |= value >> 2;
		value |= value >> 4;
		value |= value >> 8;
		value |= value >> 16;
		value ++;

		return value;

	}

};

// File:src/math/Spline.js

/**
 * 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,
			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;

	};

};

// File:src/math/Triangle.js

/**
 * @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 );

	}

};

// File:src/core/Clock.js

/**
 * @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 = self.performance !== undefined && self.performance.now !== undefined
					 ? self.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 = self.performance !== undefined && self.performance.now !== undefined
					 ? self.performance.now()
					 : Date.now();

			diff = 0.001 * ( newTime - this.oldTime );
			this.oldTime = newTime;

			this.elapsedTime += diff;

		}

		return diff;

	}

};

// File:src/core/EventDispatcher.js

/**
 * https://github.com/mrdoob/eventdispatcher.js/
 */

THREE.EventDispatcher = function () {}

THREE.EventDispatcher.prototype = {

	constructor: THREE.EventDispatcher,

	apply: function ( object ) {

		object.addEventListener = THREE.EventDispatcher.prototype.addEventListener;
		object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;
		object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;
		object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;

	},

	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 listenerArray = listeners[ type ];

		if ( listenerArray !== undefined ) {

			var index = listenerArray.indexOf( listener );

			if ( index !== - 1 ) {

				listenerArray.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;

			var array = [];
			var length = listenerArray.length;

			for ( var i = 0; i < length; i ++ ) {

				array[ i ] = listenerArray[ i ];

			}

			for ( var i = 0; i < length; i ++ ) {

				array[ i ].call( this, event );

			}

		}

	}

};

// File:src/core/Raycaster.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author bhouston / http://exocortex.com/
 * @author stephomi / http://stephaneginier.com/
 */

( function ( THREE ) {

	THREE.Raycaster = function ( origin, direction, near, far ) {

		this.ray = new THREE.Ray( origin, direction );
		// direction is assumed to be normalized (for accurate distance calculations)

		this.near = near || 0;
		this.far = far || Infinity;

		this.params = {
			Sprite: {},
			Mesh: {},
			PointCloud: { threshold: 1 },
			LOD: {},
			Line: {}
		};

	};

	var descSort = function ( a, b ) {

		return a.distance - b.distance;

	};

	var intersectObject = function ( object, raycaster, intersects, recursive ) {

		object.raycast( raycaster, intersects );

		if ( recursive === true ) {

			var children = object.children;

			for ( var i = 0, l = children.length; i < l; i ++ ) {

				intersectObject( children[ i ], raycaster, intersects, true );

			}

		}

	};

	//

	THREE.Raycaster.prototype = {

		constructor: THREE.Raycaster,

		precision: 0.0001,
		linePrecision: 1,

		set: function ( origin, direction ) {

			// direction is assumed to be normalized (for accurate distance calculations)

			this.ray.set( origin, direction );

		},

		setFromCamera: function ( coords, camera ) {

			// camera is assumed _not_ to be a child of a transformed object

			if ( camera instanceof THREE.PerspectiveCamera ) {

				this.ray.origin.copy( camera.position );
				this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( camera.position ).normalize();

			} else if ( camera instanceof THREE.OrthographicCamera ) {

				this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera );
				this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );

			} else {

				THREE.error( 'THREE.Raycaster: Unsupported camera type.' );

			}

		},

		intersectObject: function ( object, recursive ) {

			var intersects = [];

			intersectObject( object, this, intersects, recursive );

			intersects.sort( descSort );

			return intersects;

		},

		intersectObjects: function ( objects, recursive ) {

			var intersects = [];

			if ( objects instanceof Array === false ) {

				THREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
				return intersects;

			}

			for ( var i = 0, l = objects.length; i < l; i ++ ) {

				intersectObject( objects[ i ], this, intersects, recursive );

			}

			intersects.sort( descSort );

			return intersects;

		}

	};

}( THREE ) );

// File:src/core/Object3D.js

/**
 * @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 () {

	Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } );

	this.uuid = THREE.Math.generateUUID();

	this.name = '';
	this.type = 'Object3D';

	this.parent = undefined;
	this.children = [];

	this.up = THREE.Object3D.DefaultUp.clone();

	var position = new THREE.Vector3();
	var rotation = new THREE.Euler();
	var quaternion = new THREE.Quaternion();
	var scale = new THREE.Vector3( 1, 1, 1 );

	var onRotationChange = function () {
		quaternion.setFromEuler( rotation, false );
	};

	var onQuaternionChange = function () {
		rotation.setFromQuaternion( quaternion, undefined, false );
	};

	rotation.onChange( onRotationChange );
	quaternion.onChange( onQuaternionChange );

	Object.defineProperties( this, {
		position: {
			enumerable: true,
			value: position
		},
		rotation: {
			enumerable: true,
			value: rotation
		},
		quaternion: {
			enumerable: true,
			value: quaternion
		},
		scale: {
			enumerable: true,
			value: scale
		}
	} );

	this.rotationAutoUpdate = true;

	this.matrix = new THREE.Matrix4();
	this.matrixWorld = new THREE.Matrix4();

	this.matrixAutoUpdate = true;
	this.matrixWorldNeedsUpdate = false;

	this.visible = true;

	this.castShadow = false;
	this.receiveShadow = false;

	this.frustumCulled = true;
	this.renderOrder = 0;

	this.userData = {};

};

THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 );

THREE.Object3D.prototype = {

	constructor: THREE.Object3D,

	get eulerOrder () {

		THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );

		return this.rotation.order;

	},

	set eulerOrder ( value ) {

		THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );

		this.rotation.order = value;

	},

	get useQuaternion () {

		THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );

	},

	set useQuaternion ( value ) {

		THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );

	},

	applyMatrix: function ( matrix ) {

		this.matrix.multiplyMatrices( matrix, this.matrix );

		this.matrix.decompose( this.position, this.quaternion, this.scale );

	},

	setRotationFromAxisAngle: function ( axis, angle ) {

		// assumes axis is normalized

		this.quaternion.setFromAxisAngle( axis, angle );

	},

	setRotationFromEuler: function ( euler ) {

		this.quaternion.setFromEuler( euler, true );

	},

	setRotationFromMatrix: function ( m ) {

		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

		this.quaternion.setFromRotationMatrix( m );

	},

	setRotationFromQuaternion: function ( q ) {

		// assumes q is normalized

		this.quaternion.copy( q );

	},

	rotateOnAxis: function () {

		// rotate object on axis in object space
		// axis is assumed to be normalized

		var q1 = new THREE.Quaternion();

		return function ( axis, angle ) {

			q1.setFromAxisAngle( axis, angle );

			this.quaternion.multiply( q1 );

			return this;

		}

	}(),

	rotateX: function () {

		var v1 = new THREE.Vector3( 1, 0, 0 );

		return function ( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateY: function () {

		var v1 = new THREE.Vector3( 0, 1, 0 );

		return function ( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateZ: function () {

		var v1 = new THREE.Vector3( 0, 0, 1 );

		return function ( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	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 ).applyQuaternion( this.quaternion );

			this.position.add( v1.multiplyScalar( distance ) );

			return this;

		}

	}(),

	translate: function ( distance, axis ) {

		THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
		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 );

			this.quaternion.setFromRotationMatrix( m1 );

		};

	}(),

	add: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.add( arguments[ i ] );

			}

			return this;

		};

		if ( object === this ) {

			THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
			return this;

		}

		if ( object instanceof THREE.Object3D ) {

			if ( object.parent !== undefined ) {

				object.parent.remove( object );

			}

			object.parent = this;
			object.dispatchEvent( { type: 'added' } );

			this.children.push( object );

		} else {

			THREE.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );

		}

		return this;

	},

	remove: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.remove( arguments[ i ] );

			}

		};

		var index = this.children.indexOf( object );

		if ( index !== - 1 ) {

			object.parent = undefined;

			object.dispatchEvent( { type: 'removed' } );

			this.children.splice( index, 1 );

		}

	},

	getChildByName: function ( name ) {

		THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
		return this.getObjectByName( name );

	},

	getObjectById: function ( id ) {

		return this.getObjectByProperty( 'id', id );

	},

	getObjectByName: function ( name ) {

		return this.getObjectByProperty( 'name', name );

	},

	getObjectByProperty: function ( name, value ) {

		if ( this[ name ] === value ) return this;

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			var child = this.children[ i ];
			var object = child.getObjectByProperty( name, value );

			if ( object !== undefined ) {

				return object;

			}

		}

		return undefined;

	},

	getWorldPosition: function ( optionalTarget ) {

		var result = optionalTarget || new THREE.Vector3();

		this.updateMatrixWorld( true );

		return result.setFromMatrixPosition( this.matrixWorld );

	},

	getWorldQuaternion: function () {

		var position = new THREE.Vector3();
		var scale = new THREE.Vector3();

		return function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Quaternion();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, result, scale );

			return result;

		}

	}(),

	getWorldRotation: function () {

		var quaternion = new THREE.Quaternion();

		return function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Euler();

			this.getWorldQuaternion( quaternion );

			return result.setFromQuaternion( quaternion, this.rotation.order, false );

		}

	}(),

	getWorldScale: function () {

		var position = new THREE.Vector3();
		var quaternion = new THREE.Quaternion();

		return function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, quaternion, result );

			return result;

		}

	}(),

	getWorldDirection: function () {

		var quaternion = new THREE.Quaternion();

		return function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();

			this.getWorldQuaternion( quaternion );

			return result.set( 0, 0, 1 ).applyQuaternion( quaternion );

		}

	}(),

	raycast: function () {},

	traverse: function ( callback ) {

		callback( this );

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			this.children[ i ].traverse( callback );

		}

	},

	traverseVisible: function ( callback ) {

		if ( this.visible === false ) return;

		callback( this );

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			this.children[ i ].traverseVisible( callback );

		}

	},

	traverseAncestors: function ( callback ) {

		if ( this.parent ) {

			callback( this.parent );

			this.parent.traverseAncestors( callback );

		}

	},

	updateMatrix: function () {

		this.matrix.compose( 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 );

		}

	},

	toJSON: function () {

		var output = {
			metadata: {
				version: 4.3,
				type: 'Object',
				generator: 'ObjectExporter'
			}
		};

		//

		var geometries = {};

		var parseGeometry = function ( geometry ) {

			if ( output.geometries === undefined ) {

				output.geometries = [];

			}

			if ( geometries[ geometry.uuid ] === undefined ) {

				var json = geometry.toJSON();

				delete json.metadata;

				geometries[ geometry.uuid ] = json;

				output.geometries.push( json );

			}

			return geometry.uuid;

		};

		//

		var materials = {};

		var parseMaterial = function ( material ) {

			if ( output.materials === undefined ) {

				output.materials = [];

			}

			if ( materials[ material.uuid ] === undefined ) {

				var json = material.toJSON();

				delete json.metadata;

				materials[ material.uuid ] = json;

				output.materials.push( json );

			}

			return material.uuid;

		};

		//

		var parseObject = function ( object ) {

			var data = {};

			data.uuid = object.uuid;
			data.type = object.type;

			if ( object.name !== '' ) data.name = object.name;
			if ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData;
			if ( object.visible !== true ) data.visible = object.visible;

			if ( object instanceof THREE.PerspectiveCamera ) {

				data.fov = object.fov;
				data.aspect = object.aspect;
				data.near = object.near;
				data.far = object.far;

			} else if ( object instanceof THREE.OrthographicCamera ) {

				data.left = object.left;
				data.right = object.right;
				data.top = object.top;
				data.bottom = object.bottom;
				data.near = object.near;
				data.far = object.far;

			} else if ( object instanceof THREE.AmbientLight ) {

				data.color = object.color.getHex();

			} else if ( object instanceof THREE.DirectionalLight ) {

				data.color = object.color.getHex();
				data.intensity = object.intensity;

			} else if ( object instanceof THREE.PointLight ) {

				data.color = object.color.getHex();
				data.intensity = object.intensity;
				data.distance = object.distance;
				data.decay = object.decay;

			} else if ( object instanceof THREE.SpotLight ) {

				data.color = object.color.getHex();
				data.intensity = object.intensity;
				data.distance = object.distance;
				data.angle = object.angle;
				data.exponent = object.exponent;
				data.decay = object.decay;

			} else if ( object instanceof THREE.HemisphereLight ) {

				data.color = object.color.getHex();
				data.groundColor = object.groundColor.getHex();

			} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) {

				data.geometry = parseGeometry( object.geometry );
				data.material = parseMaterial( object.material );

				if ( object instanceof THREE.Line ) data.mode = object.mode;

			} else if ( object instanceof THREE.Sprite ) {

				data.material = parseMaterial( object.material );

			}

			data.matrix = object.matrix.toArray();

			if ( object.children.length > 0 ) {

				data.children = [];

				for ( var i = 0; i < object.children.length; i ++ ) {

					data.children.push( parseObject( object.children[ i ] ) );

				}

			}

			return data;

		}

		output.object = parseObject( this );

		return output;

	},

	clone: function ( object, recursive ) {

		if ( object === undefined ) object = new THREE.Object3D();
		if ( recursive === undefined ) recursive = true;

		object.name = this.name;

		object.up.copy( this.up );

		object.position.copy( this.position );
		object.quaternion.copy( this.quaternion );
		object.scale.copy( this.scale );

		object.rotationAutoUpdate = this.rotationAutoUpdate;

		object.matrix.copy( this.matrix );
		object.matrixWorld.copy( this.matrixWorld );

		object.matrixAutoUpdate = this.matrixAutoUpdate;
		object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;

		object.visible = this.visible;

		object.castShadow = this.castShadow;
		object.receiveShadow = this.receiveShadow;

		object.frustumCulled = this.frustumCulled;

		object.userData = JSON.parse( JSON.stringify( this.userData ) );

		if ( recursive === true ) {

			for ( var i = 0; i < this.children.length; i ++ ) {

				var child = this.children[ i ];
				object.add( child.clone() );

			}

		}

		return object;

	}

};

THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );

THREE.Object3DIdCount = 0;

// File:src/core/Face3.js

/**
 * @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;

};

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.materialIndex = this.materialIndex;

		for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) {

			face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();

		}

		for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) {

			face.vertexColors[ i ] = this.vertexColors[ i ].clone();

		}

		for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) {

			face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();

		}

		return face;

	}

};

// File:src/core/Face4.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {

	THREE.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' )
	return new THREE.Face3( a, b, c, normal, color, materialIndex );

};

// File:src/core/BufferAttribute.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.BufferAttribute = function ( array, itemSize ) {

	this.array = array;
	this.itemSize = itemSize;

	this.needsUpdate = false;

};

THREE.BufferAttribute.prototype = {

	constructor: THREE.BufferAttribute,

	get length () {

		return this.array.length;

	},

	copyAt: function ( index1, attribute, index2 ) {

		index1 *= this.itemSize;
		index2 *= attribute.itemSize;

		for ( var i = 0, l = this.itemSize; i < l; i ++ ) {

			this.array[ index1 + i ] = attribute.array[ index2 + i ];

		}

		return this;

	},

	set: function ( value, offset ) {

		if ( offset === undefined ) offset = 0;

		this.array.set( value, offset );

		return this;

	},

	setX: function ( index, x ) {

		this.array[ index * this.itemSize ] = x;

		return this;

	},

	setY: function ( index, y ) {

		this.array[ index * this.itemSize + 1 ] = y;

		return this;

	},

	setZ: function ( index, z ) {

		this.array[ index * this.itemSize + 2 ] = z;

		return this;

	},

	setXY: function ( index, x, y ) {

		index *= this.itemSize;

		this.array[ index     ] = x;
		this.array[ index + 1 ] = y;

		return this;

	},

	setXYZ: function ( index, x, y, z ) {

		index *= this.itemSize;

		this.array[ index     ] = x;
		this.array[ index + 1 ] = y;
		this.array[ index + 2 ] = z;

		return this;

	},

	setXYZW: function ( index, x, y, z, w ) {

		index *= this.itemSize;

		this.array[ index     ] = x;
		this.array[ index + 1 ] = y;
		this.array[ index + 2 ] = z;
		this.array[ index + 3 ] = w;

		return this;

	},

	clone: function () {

		return new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize );

	}

};

//

THREE.Int8Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Uint8Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Uint8ClampedAttribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );


};

THREE.Int16Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Uint16Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Int32Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Uint32Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Float32Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

THREE.Float64Attribute = function ( data, itemSize ) {

	THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
	return new THREE.BufferAttribute( data, itemSize );

};

// File:src/core/DynamicBufferAttribute.js

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 * @author mrdoob / http://mrdoob.com/
 */

THREE.DynamicBufferAttribute = function ( array, itemSize ) {

	THREE.BufferAttribute.call( this, array, itemSize );

	this.updateRange = { offset: 0, count: -1 };

};

THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype );
THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute;

THREE.DynamicBufferAttribute.prototype.clone = function () {

	return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize );

};

// File:src/core/BufferGeometry.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.BufferGeometry = function () {

	Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );

	this.uuid = THREE.Math.generateUUID();

	this.name = '';
	this.type = 'BufferGeometry';

	this.attributes = {};
	this.attributesKeys = [];

	this.drawcalls = [];
	this.offsets = this.drawcalls; // backwards compatibility

	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.BufferGeometry.prototype = {

	constructor: THREE.BufferGeometry,

	addAttribute: function ( name, attribute ) {

		if ( attribute instanceof THREE.BufferAttribute === false ) {

			THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );

			this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };

			return;

		}

		this.attributes[ name ] = attribute;
		this.attributesKeys = Object.keys( this.attributes );

	},

	getAttribute: function ( name ) {

		return this.attributes[ name ];

	},

	addDrawCall: function ( start, count, indexOffset ) {

		this.drawcalls.push( {

			start: start,
			count: count,
			index: indexOffset !== undefined ? indexOffset : 0

		} );

	},

	applyMatrix: function ( matrix ) {

		var position = this.attributes.position;

		if ( position !== undefined ) {

			matrix.applyToVector3Array( position.array );
			position.needsUpdate = true;

		}

		var normal = this.attributes.normal;

		if ( normal !== undefined ) {

			var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );

			normalMatrix.applyToVector3Array( normal.array );
			normal.needsUpdate = true;

		}

		if ( this.boundingBox !== null ) {

			this.computeBoundingBox();

		}

		if ( this.boundingSphere !== null ) {

			this.computeBoundingSphere();

		}

	},

	center: function () {

		this.computeBoundingBox();

		var offset = this.boundingBox.center().negate();

		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );

		return offset;

	},

	fromGeometry: function ( geometry, settings ) {

		settings = settings || { 'vertexColors': THREE.NoColors };

		var vertices = geometry.vertices;
		var faces = geometry.faces;
		var faceVertexUvs = geometry.faceVertexUvs;
		var vertexColors = settings.vertexColors;
		var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;
		var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;

		var positions = new Float32Array( faces.length * 3 * 3 );
		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

		var normals = new Float32Array( faces.length * 3 * 3 );
		this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );

		if ( vertexColors !== THREE.NoColors ) {

			var colors = new Float32Array( faces.length * 3 * 3 );
			this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

		}

		if ( hasFaceVertexUv === true ) {

			var uvs = new Float32Array( faces.length * 3 * 2 );
			this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

		}

		for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {

			var face = faces[ i ];

			var a = vertices[ face.a ];
			var b = vertices[ face.b ];
			var c = vertices[ face.c ];

			positions[ i3     ] = a.x;
			positions[ i3 + 1 ] = a.y;
			positions[ i3 + 2 ] = a.z;

			positions[ i3 + 3 ] = b.x;
			positions[ i3 + 4 ] = b.y;
			positions[ i3 + 5 ] = b.z;

			positions[ i3 + 6 ] = c.x;
			positions[ i3 + 7 ] = c.y;
			positions[ i3 + 8 ] = c.z;

			if ( hasFaceVertexNormals === true ) {

				var na = face.vertexNormals[ 0 ];
				var nb = face.vertexNormals[ 1 ];
				var nc = face.vertexNormals[ 2 ];

				normals[ i3     ] = na.x;
				normals[ i3 + 1 ] = na.y;
				normals[ i3 + 2 ] = na.z;

				normals[ i3 + 3 ] = nb.x;
				normals[ i3 + 4 ] = nb.y;
				normals[ i3 + 5 ] = nb.z;

				normals[ i3 + 6 ] = nc.x;
				normals[ i3 + 7 ] = nc.y;
				normals[ i3 + 8 ] = nc.z;

			} else {

				var n = face.normal;

				normals[ i3     ] = n.x;
				normals[ i3 + 1 ] = n.y;
				normals[ i3 + 2 ] = n.z;

				normals[ i3 + 3 ] = n.x;
				normals[ i3 + 4 ] = n.y;
				normals[ i3 + 5 ] = n.z;

				normals[ i3 + 6 ] = n.x;
				normals[ i3 + 7 ] = n.y;
				normals[ i3 + 8 ] = n.z;

			}

			if ( vertexColors === THREE.FaceColors ) {

				var fc = face.color;

				colors[ i3     ] = fc.r;
				colors[ i3 + 1 ] = fc.g;
				colors[ i3 + 2 ] = fc.b;

				colors[ i3 + 3 ] = fc.r;
				colors[ i3 + 4 ] = fc.g;
				colors[ i3 + 5 ] = fc.b;

				colors[ i3 + 6 ] = fc.r;
				colors[ i3 + 7 ] = fc.g;
				colors[ i3 + 8 ] = fc.b;

			} else if ( vertexColors === THREE.VertexColors ) {

				var vca = face.vertexColors[ 0 ];
				var vcb = face.vertexColors[ 1 ];
				var vcc = face.vertexColors[ 2 ];

				colors[ i3     ] = vca.r;
				colors[ i3 + 1 ] = vca.g;
				colors[ i3 + 2 ] = vca.b;

				colors[ i3 + 3 ] = vcb.r;
				colors[ i3 + 4 ] = vcb.g;
				colors[ i3 + 5 ] = vcb.b;

				colors[ i3 + 6 ] = vcc.r;
				colors[ i3 + 7 ] = vcc.g;
				colors[ i3 + 8 ] = vcc.b;

			}

			if ( hasFaceVertexUv === true ) {

				var uva = faceVertexUvs[ 0 ][ i ][ 0 ];
				var uvb = faceVertexUvs[ 0 ][ i ][ 1 ];
				var uvc = faceVertexUvs[ 0 ][ i ][ 2 ];

				uvs[ i2     ] = uva.x;
				uvs[ i2 + 1 ] = uva.y;

				uvs[ i2 + 2 ] = uvb.x;
				uvs[ i2 + 3 ] = uvb.y;

				uvs[ i2 + 4 ] = uvc.x;
				uvs[ i2 + 5 ] = uvc.y;

			}

		}

		this.computeBoundingSphere()

		return this;

	},

	computeBoundingBox: function () {

		var vector = new THREE.Vector3();

		return function () {

			if ( this.boundingBox === null ) {

				this.boundingBox = new THREE.Box3();

			}

			var positions = this.attributes.position.array;

			if ( positions ) {

				var bb = this.boundingBox;
				bb.makeEmpty();

				for ( var i = 0, il = positions.length; i < il; i += 3 ) {

					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					bb.expandByPoint( vector );

				}

			}

			if ( positions === undefined || positions.length === 0 ) {

				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );

			}

			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {

				THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' );

			}

		}

	}(),

	computeBoundingSphere: function () {

		var box = new THREE.Box3();
		var vector = new THREE.Vector3();

		return function () {

			if ( this.boundingSphere === null ) {

				this.boundingSphere = new THREE.Sphere();

			}

			var positions = this.attributes.position.array;

			if ( positions ) {

				box.makeEmpty();

				var center = this.boundingSphere.center;

				for ( var i = 0, il = positions.length; i < il; i += 3 ) {

					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					box.expandByPoint( vector );

				}

				box.center( center );

				// hoping to find a boundingSphere with a radius smaller than the
				// boundingSphere of the boundingBox:  sqrt(3) smaller in the best case

				var maxRadiusSq = 0;

				for ( var i = 0, il = positions.length; i < il; i += 3 ) {

					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );

				}

				this.boundingSphere.radius = Math.sqrt( maxRadiusSq );

				if ( isNaN( this.boundingSphere.radius ) ) {

					THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );

				}

			}

		}

	}(),

	computeFaceNormals: function () {

		// backwards compatibility

	},

	computeVertexNormals: function () {

		var attributes = this.attributes;

		if ( attributes.position ) {

			var positions = attributes.position.array;

			if ( attributes.normal === undefined ) {

				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );

			} else {

				// reset existing normals to zero

				var normals = attributes.normal.array;

				for ( var i = 0, il = normals.length; i < il; i ++ ) {

					normals[ i ] = 0;

				}

			}

			var normals = attributes.normal.array;

			var vA, vB, vC,

			pA = new THREE.Vector3(),
			pB = new THREE.Vector3(),
			pC = new THREE.Vector3(),

			cb = new THREE.Vector3(),
			ab = new THREE.Vector3();

			// indexed elements

			if ( attributes.index ) {

				var indices = attributes.index.array;

				var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );

				for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {

					var start = offsets[ j ].start;
					var count = offsets[ j ].count;
					var index = offsets[ j ].index;

					for ( var i = start, il = start + count; i < il; i += 3 ) {

						vA = ( index + indices[ i     ] ) * 3;
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;

						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );

						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );

						normals[ vA     ] += cb.x;
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;

						normals[ vB     ] += cb.x;
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;

						normals[ vC     ] += cb.x;
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;

					}

				}

			} else {

				// non-indexed elements (unconnected triangle soup)

				for ( var i = 0, il = positions.length; i < il; i += 9 ) {

					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );

					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();

			attributes.normal.needsUpdate = true;

		}

	},

	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 ) {

			THREE.warn( 'THREE.BufferGeometry: 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 ) {

			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );

		}

		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 vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),

			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),

			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 ) {

			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );

			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );

			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 );

		}

		var i, il;
		var j, jl;
		var iA, iB, iC;

		if ( this.drawcalls.length === 0 ) {

			this.addDrawCall( 0, indices.length, 0 );

		}

		var drawcalls = this.drawcalls;

		for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {

			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ 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.fromArray( normals, v * 3 );
			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 = drawcalls.length; j < jl; ++ j ) {

			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ 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 );

			}

		}

	},

	/*
	Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
	This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
	WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
	size - Defaults to 65535, but allows for larger or smaller chunks.
	*/
	computeOffsets: function ( size ) {

		if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit.

		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;

		var facesCount = ( indices.length / 3 );

		/*
		console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
		console.log("Faces to process: "+(indices.length/3));
		console.log("Reordering "+verticesCount+" vertices.");
		*/

		var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
		var indexPtr = 0;
		var vertexPtr = 0;

		var offsets = [ { start:0, count:0, index:0 } ];
		var offset = offsets[ 0 ];

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
		var faceVertices = new Int32Array( 6 );
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }

		/*
			Traverse every face and reorder vertices in the proper offsets of 65k.
			We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
		*/
		for ( var findex = 0; findex < facesCount; findex ++ ) {
			newVerticeMaps = 0;

			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
				if ( vertexMap[ vid ] == - 1 ) {
					//Unmapped vertice
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
					//Reused vertices from previous block (duplicate)
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
				} else {
					//Reused vertice in the current block
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
			if ( faceMax > ( offset.index + size ) ) {
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
				offsets.push( new_offset );
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
				for ( var v = 0; v < 6; v += 2 ) {
					var new_vid = faceVertices[ v + 1 ];
					if ( new_vid > - 1 && new_vid < offset.index )
						faceVertices[ v + 1 ] = - 1;
				}
			}

			//Reindex the face.
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];

				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;

				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
			}
		}

		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
		this.offsets = offsets; // TODO: Deprecate
		this.drawcalls = offsets;

		/*
		var orderTime = Date.now();
		console.log("Reorder time: "+(orderTime-s)+"ms");
		console.log("Duplicated "+duplicatedVertices+" vertices.");
		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
		console.log("Draw offsets: "+offsets.length);
		*/

		return offsets;

	},

	merge: function ( geometry, offset ) {

		if ( geometry instanceof THREE.BufferGeometry === false ) {

			THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
			return;

		}

		if ( offset === undefined ) offset = 0;

		var attributes = this.attributes;

		for ( var key in attributes ) {

			if ( geometry.attributes[ key ] === undefined ) continue;

			var attribute1 = attributes[ key ];
			var attributeArray1 = attribute1.array;

			var attribute2 = geometry.attributes[ key ];
			var attributeArray2 = attribute2.array;

			var attributeSize = attribute2.itemSize;

			for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {

				attributeArray1[ j ] = attributeArray2[ i ];

			}

		}

		return this;

	},

	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;

		}

	},

	/*
		reoderBuffers:
		Reorder attributes based on a new indexBuffer and indexMap.
		indexBuffer - Uint16Array of the new ordered indices.
		indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
	*/
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
		for ( var attr in this.attributes ) {
			if ( attr == 'index' )
				continue;
			var sourceArray = this.attributes[ attr ].array;
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
		}

		/* Move attribute positions based on the new index map */
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
			for ( var attr in this.attributes ) {
				if ( attr == 'index' )
					continue;
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
		this.attributes[ 'index' ].array = indexBuffer;
		for ( var attr in this.attributes ) {
			if ( attr == 'index' )
				continue;
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
		}
	},

	toJSON: function () {

		var output = {
			metadata: {
				version: 4.0,
				type: 'BufferGeometry',
				generator: 'BufferGeometryExporter'
			},
			uuid: this.uuid,
			type: this.type,
			data: {
				attributes: {}
			}
		};

		var attributes = this.attributes;
		var offsets = this.offsets;
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

			var array = Array.prototype.slice.call( attribute.array );

			output.data.attributes[ key ] = {
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
			}

		}

		if ( offsets.length > 0 ) {

			output.data.offsets = JSON.parse( JSON.stringify( offsets ) );

		}

		if ( boundingSphere !== null ) {

			output.data.boundingSphere = {
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
			}

		}

		return output;

	},

	clone: function () {

		var geometry = new THREE.BufferGeometry();

		for ( var attr in this.attributes ) {

			var sourceAttr = this.attributes[ attr ];
			geometry.addAttribute( attr, sourceAttr.clone() );

		}

		for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {

			var offset = this.offsets[ i ];

			geometry.offsets.push( {

				start: offset.start,
				index: offset.index,
				count: offset.count

			} );

		}

		return geometry;

	},

	dispose: function () {

		this.dispatchEvent( { type: 'dispose' } );

	}

};

THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );

// File:src/core/Geometry.js

/**
 * @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 () {

	Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );

	this.uuid = THREE.Math.generateUUID();

	this.name = '';
	this.type = 'Geometry';

	this.vertices = [];
	this.colors = [];  // one-to-one vertex colors, used in Points and Line

	this.faces = [];

	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.groupsNeedUpdate = false;

};

THREE.Geometry.prototype = {

	constructor: THREE.Geometry,

	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();

			}

		}

		if ( this.boundingBox !== null ) {

			this.computeBoundingBox();

		}

		if ( this.boundingSphere !== null ) {

			this.computeBoundingSphere();

		}

		this.verticesNeedUpdate = true;
		this.normalsNeedUpdate = true;

	},

	fromBufferGeometry: function ( geometry ) {

		var scope = this;

		var attributes = geometry.attributes;

		var vertices = attributes.position.array;
		var indices = attributes.index !== undefined ? attributes.index.array : undefined;
		var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
		var colors = attributes.color !== undefined ? attributes.color.array : undefined;
		var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;

		var tempNormals = [];
		var tempUVs = [];

		for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) {

			scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );

			if ( normals !== undefined ) {

				tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );

			}

			if ( colors !== undefined ) {

				scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );

			}

			if ( uvs !== undefined ) {

				tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) );

			}

		}

		var addFace = function ( a, b, c ) {

			var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];
			var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];

			scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) );

			if ( uvs !== undefined ) {

				scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );

			}

		};

		if ( indices !== undefined ) {

			var drawcalls = geometry.drawcalls;

			if ( drawcalls.length > 0 ) {

				for ( var i = 0; i < drawcalls.length; i ++ ) {

					var drawcall = drawcalls[ i ];

					var start = drawcall.start;
					var count = drawcall.count;
					var index = drawcall.index;

					for ( var j = start, jl = start + count; j < jl; j += 3 ) {

						addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] );

					}

				}

			} else {

				for ( var i = 0; i < indices.length; i += 3 ) {

					addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );

				}

			}

		} else {

			for ( var i = 0; i < vertices.length / 3; i += 3 ) {

				addFace( i, i + 1, i + 2 );

			}

		}

		this.computeFaceNormals();

		if ( geometry.boundingBox !== null ) {

			this.boundingBox = geometry.boundingBox.clone();

		}

		if ( geometry.boundingSphere !== null ) {

			this.boundingSphere = geometry.boundingSphere.clone();

		}

		return this;

	},

	center: function () {

		this.computeBoundingBox();

		var offset = this.boundingBox.center().negate();

		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );

		return offset;

	},

	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;

		vertices = new Array( this.vertices.length );

		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

			vertices[ v ] = new THREE.Vector3();

		}

		if ( areaWeighted ) {

			// vertex normals weighted by triangle areas
			// http://www.iquilezles.org/www/articles/normals/normals.htm

			var vA, vB, vC;
			var cb = new THREE.Vector3(), ab = new THREE.Vector3();

			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

				face = this.faces[ f ];

				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 {

			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

				face = this.faces[ f ];

				vertices[ face.a ].add( face.normal );
				vertices[ face.b ].add( face.normal );
				vertices[ face.c ].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 ];

			face.vertexNormals[ 0 ] = vertices[ face.a ].clone();
			face.vertexNormals[ 1 ] = vertices[ face.b ].clone();
			face.vertexNormals[ 2 ] = vertices[ face.c ].clone();

		}

	},

	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 ++ ) {

					faceNormal = new THREE.Vector3();
					vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: 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 );

				vertexNormals.a.copy( face.vertexNormals[ 0 ] );
				vertexNormals.b.copy( face.vertexNormals[ 1 ] );
				vertexNormals.c.copy( face.vertexNormals[ 2 ] );

			}

		}

		// 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, 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

			handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );

		}

		var faceIndex = [ 'a', 'b', 'c', 'd' ];

		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

			face = this.faces[ f ];

			for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); 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.setFromPoints( this.vertices );

	},

	merge: function ( geometry, matrix, materialIndexOffset ) {

		if ( geometry instanceof THREE.Geometry === false ) {

			THREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
			return;

		}

		var normalMatrix,
		vertexOffset = this.vertices.length,
		vertices1 = this.vertices,
		vertices2 = geometry.vertices,
		faces1 = this.faces,
		faces2 = geometry.faces,
		uvs1 = this.faceVertexUvs[ 0 ],
		uvs2 = geometry.faceVertexUvs[ 0 ];

		if ( materialIndexOffset === undefined ) materialIndexOffset = 0;

		if ( matrix !== undefined ) {

			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 !== undefined ) 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;

			faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
			faceCopy.normal.copy( face.normal );

			if ( normalMatrix !== undefined ) {

				faceCopy.normal.applyMatrix3( normalMatrix ).normalize();

			}

			for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {

				normal = faceVertexNormals[ j ].clone();

				if ( normalMatrix !== undefined ) {

					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;

			faces1.push( faceCopy );

		}

		// uvs

		for ( i = 0, il = uvs2.length; i < il; i ++ ) {

			var uv = uvs2[ i ], uvCopy = [];

			if ( uv === undefined ) {

				continue;

			}

			for ( var j = 0, jl = uv.length; j < jl; j ++ ) {

				uvCopy.push( uv[ j ].clone() );

			}

			uvs1.push( uvCopy );

		}

	},

	mergeMesh: function ( mesh ) {

		if ( mesh instanceof THREE.Mesh === false ) {

			THREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
			return;

		}

		mesh.matrixAutoUpdate && mesh.updateMatrix();

		this.merge( mesh.geometry, mesh.matrix );

	},

	/*
	 * 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, j, jl;

		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 );

			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 ];

			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;

				}
			}

		}

		for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
			var idx = faceIndicesToRemove[ i ];

			this.faces.splice( idx, 1 );

			for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {

				this.faceVertexUvs[ j ].splice( idx, 1 );

			}

		}

		// Use unique set of vertices

		var diff = this.vertices.length - unique.length;
		this.vertices = unique;
		return diff;

	},

	toJSON: function () {

		var output = {
			metadata: {
				version: 4.0,
				type: 'BufferGeometry',
				generator: 'BufferGeometryExporter'
			},
			uuid: this.uuid,
			type: this.type
		};

		if ( this.name !== "" ) output.name = this.name;

		if ( this.parameters !== undefined ) {

			var parameters = this.parameters;

			for ( var key in parameters ) {

				if ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ];

			}

			return output;

		}

		var vertices = [];

		for ( var i = 0; i < this.vertices.length; i ++ ) {

			var vertex = this.vertices[ i ];
			vertices.push( vertex.x, vertex.y, vertex.z );

		}

		var faces = [];
		var normals = [];
		var normalsHash = {};
		var colors = [];
		var colorsHash = {};
		var uvs = [];
		var uvsHash = {};

		for ( var i = 0; i < this.faces.length; i ++ ) {

			var face = this.faces[ i ];

			var hasMaterial = false; // face.materialIndex !== undefined;
			var hasFaceUv = false; // deprecated
			var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
			var hasFaceNormal = face.normal.length() > 0;
			var hasFaceVertexNormal = face.vertexNormals.length > 0;
			var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
			var hasFaceVertexColor = face.vertexColors.length > 0;

			var faceType = 0;

			faceType = setBit( faceType, 0, 0 );
			faceType = setBit( faceType, 1, hasMaterial );
			faceType = setBit( faceType, 2, hasFaceUv );
			faceType = setBit( faceType, 3, hasFaceVertexUv );
			faceType = setBit( faceType, 4, hasFaceNormal );
			faceType = setBit( faceType, 5, hasFaceVertexNormal );
			faceType = setBit( faceType, 6, hasFaceColor );
			faceType = setBit( faceType, 7, hasFaceVertexColor );

			faces.push( faceType );
			faces.push( face.a, face.b, face.c );


			/*
			if ( hasMaterial ) {

				faces.push( face.materialIndex );

			}
			*/

			if ( hasFaceVertexUv ) {

				var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];

				faces.push(
					getUvIndex( faceVertexUvs[ 0 ] ),
					getUvIndex( faceVertexUvs[ 1 ] ),
					getUvIndex( faceVertexUvs[ 2 ] )
				);

			}

			if ( hasFaceNormal ) {

				faces.push( getNormalIndex( face.normal ) );

			}

			if ( hasFaceVertexNormal ) {

				var vertexNormals = face.vertexNormals;

				faces.push(
					getNormalIndex( vertexNormals[ 0 ] ),
					getNormalIndex( vertexNormals[ 1 ] ),
					getNormalIndex( vertexNormals[ 2 ] )
				);

			}

			if ( hasFaceColor ) {

				faces.push( getColorIndex( face.color ) );

			}

			if ( hasFaceVertexColor ) {

				var vertexColors = face.vertexColors;

				faces.push(
					getColorIndex( vertexColors[ 0 ] ),
					getColorIndex( vertexColors[ 1 ] ),
					getColorIndex( vertexColors[ 2 ] )
				);

			}

		}

		function setBit( value, position, enabled ) {

			return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) );

		}

		function getNormalIndex( normal ) {

			var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();

			if ( normalsHash[ hash ] !== undefined ) {

				return normalsHash[ hash ];

			}

			normalsHash[ hash ] = normals.length / 3;
			normals.push( normal.x, normal.y, normal.z );

			return normalsHash[ hash ];

		}

		function getColorIndex( color ) {

			var hash = color.r.toString() + color.g.toString() + color.b.toString();

			if ( colorsHash[ hash ] !== undefined ) {

				return colorsHash[ hash ];

			}

			colorsHash[ hash ] = colors.length;
			colors.push( color.getHex() );

			return colorsHash[ hash ];

		}

		function getUvIndex( uv ) {

			var hash = uv.x.toString() + uv.y.toString();

			if ( uvsHash[ hash ] !== undefined ) {

				return uvsHash[ hash ];

			}

			uvsHash[ hash ] = uvs.length / 2;
			uvs.push( uv.x, uv.y );

			return uvsHash[ hash ];

		}

		output.data = {};

		output.data.vertices = vertices;
		output.data.normals = normals;
		if ( colors.length > 0 ) output.data.colors = colors;
		if ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility
		output.data.faces = faces;

		//

		return output;

	},

	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() );

		}

		for ( var i = 0, il = this.faceVertexUvs.length; i < il; i ++ ) {

			var faceVertexUvs = this.faceVertexUvs[ i ];

			if ( geometry.faceVertexUvs[ i ] === undefined ) {

				geometry.faceVertexUvs[ i ] = [];

			}

			for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {

				var uvs = faceVertexUvs[ j ], uvsCopy = [];

				for ( var k = 0, kl = uvs.length; k < kl; k ++ ) {

					var uv = uvs[ k ];

					uvsCopy.push( uv.clone() );

				}

				geometry.faceVertexUvs[ i ].push( uvsCopy );

			}

		}

		return geometry;

	},

	dispose: function () {

		this.dispatchEvent( { type: 'dispose' } );

	}

};

THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype );

THREE.GeometryIdCount = 0;

// File:src/cameras/Camera.js

/**
 * @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.type = 'Camera';

	this.matrixWorldInverse = new THREE.Matrix4();
	this.projectionMatrix = new THREE.Matrix4();

};

THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );
THREE.Camera.prototype.constructor = THREE.Camera;

THREE.Camera.prototype.getWorldDirection = function () {

	var quaternion = new THREE.Quaternion();

	return function ( optionalTarget ) {

		var result = optionalTarget || new THREE.Vector3();

		this.getWorldQuaternion( quaternion );

		return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );

	}

}();

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 );

		this.quaternion.setFromRotationMatrix( m1 );

	};

}();

THREE.Camera.prototype.clone = function ( camera ) {

	if ( camera === undefined ) camera = new THREE.Camera();

	THREE.Object3D.prototype.clone.call( this, camera );

	camera.matrixWorldInverse.copy( this.matrixWorldInverse );
	camera.projectionMatrix.copy( this.projectionMatrix );

	return camera;
};

// File:src/cameras/CubeCamera.js

/**
 * 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 );

	this.type = 'CubeCamera';

	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 );
THREE.CubeCamera.prototype.constructor = THREE.CubeCamera;

// File:src/cameras/OrthographicCamera.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {

	THREE.Camera.call( this );

	this.type = 'OrthographicCamera';

	this.zoom = 1;

	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.constructor = THREE.OrthographicCamera;

THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {

	var dx = ( this.right - this.left ) / ( 2 * this.zoom );
	var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
	var cx = ( this.right + this.left ) / 2;
	var cy = ( this.top + this.bottom ) / 2;

	this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far );

};

THREE.OrthographicCamera.prototype.clone = function () {

	var camera = new THREE.OrthographicCamera();

	THREE.Camera.prototype.clone.call( this, camera );

	camera.zoom = this.zoom;

	camera.left = this.left;
	camera.right = this.right;
	camera.top = this.top;
	camera.bottom = this.bottom;

	camera.near = this.near;
	camera.far = this.far;

	camera.projectionMatrix.copy( this.projectionMatrix );

	return camera;
};

// File:src/cameras/PerspectiveCamera.js

/**
 * @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.type = 'PerspectiveCamera';

	this.zoom = 1;

	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 );
THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera;


/**
 * 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 () {

	var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) );

	if ( this.fullWidth ) {

		var aspect = this.fullWidth / this.fullHeight;
		var top = Math.tan( THREE.Math.degToRad( 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( fov, this.aspect, this.near, this.far );

	}

};

THREE.PerspectiveCamera.prototype.clone = function () {

	var camera = new THREE.PerspectiveCamera();

	THREE.Camera.prototype.clone.call( this, camera );

	camera.zoom = this.zoom;

	camera.fov = this.fov;
	camera.aspect = this.aspect;
	camera.near = this.near;
	camera.far = this.far;

	camera.projectionMatrix.copy( this.projectionMatrix );

	return camera;

};

// File:src/lights/Light.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Light = function ( color ) {

	THREE.Object3D.call( this );

	this.type = 'Light';
	
	this.color = new THREE.Color( color );

};

THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
THREE.Light.prototype.constructor = THREE.Light;

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;

};

// File:src/lights/AmbientLight.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.AmbientLight = function ( color ) {

	THREE.Light.call( this, color );

	this.type = 'AmbientLight';

};

THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
THREE.AmbientLight.prototype.constructor = THREE.AmbientLight;

THREE.AmbientLight.prototype.clone = function () {

	var light = new THREE.AmbientLight();

	THREE.Light.prototype.clone.call( this, light );

	return light;

};

// File:src/lights/AreaLight.js

/**
 * @author MPanknin / http://www.redplant.de/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.AreaLight = function ( color, intensity ) {

	THREE.Light.call( this, color );

	this.type = 'AreaLight';

	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 );
THREE.AreaLight.prototype.constructor = THREE.AreaLight;


// File:src/lights/DirectionalLight.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.DirectionalLight = function ( color, intensity ) {

	THREE.Light.call( this, color );

	this.type = 'DirectionalLight';

	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.constructor = THREE.DirectionalLight;

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;

	//

	light.shadowCameraNear = this.shadowCameraNear;
	light.shadowCameraFar = this.shadowCameraFar;

	light.shadowCameraLeft = this.shadowCameraLeft;
	light.shadowCameraRight = this.shadowCameraRight;
	light.shadowCameraTop = this.shadowCameraTop;
	light.shadowCameraBottom = this.shadowCameraBottom;

	light.shadowCameraVisible = this.shadowCameraVisible;

	light.shadowBias = this.shadowBias;
	light.shadowDarkness = this.shadowDarkness;

	light.shadowMapWidth = this.shadowMapWidth;
	light.shadowMapHeight = this.shadowMapHeight;

	//

	light.shadowCascade = this.shadowCascade;

	light.shadowCascadeOffset.copy( this.shadowCascadeOffset );
	light.shadowCascadeCount = this.shadowCascadeCount;

	light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 );
	light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 );
	light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 );

	light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 );
	light.shadowCascadeFarZ  = this.shadowCascadeFarZ.slice( 0 );

	return light;

};

// File:src/lights/HemisphereLight.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) {

	THREE.Light.call( this, skyColor );

	this.type = 'HemisphereLight';

	this.position.set( 0, 100, 0 );

	this.groundColor = new THREE.Color( groundColor );
	this.intensity = ( intensity !== undefined ) ? intensity : 1;

};

THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight;

THREE.HemisphereLight.prototype.clone = function () {

	var light = new THREE.HemisphereLight();

	THREE.Light.prototype.clone.call( this, light );

	light.groundColor.copy( this.groundColor );
	light.intensity = this.intensity;

	return light;

};

// File:src/lights/PointLight.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.PointLight = function ( color, intensity, distance, decay ) {

	THREE.Light.call( this, color );

	this.type = 'PointLight';

	this.intensity = ( intensity !== undefined ) ? intensity : 1;
	this.distance = ( distance !== undefined ) ? distance : 0;
	this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.

};

THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
THREE.PointLight.prototype.constructor = THREE.PointLight;

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;
	light.decay = this.decay;

	return light;

};

// File:src/lights/SpotLight.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) {

	THREE.Light.call( this, color );

	this.type = 'SpotLight';

	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.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.

	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.constructor = THREE.SpotLight;

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.decay = this.decay;

	light.castShadow = this.castShadow;
	light.onlyShadow = this.onlyShadow;

	//

	light.shadowCameraNear = this.shadowCameraNear;
	light.shadowCameraFar = this.shadowCameraFar;
	light.shadowCameraFov = this.shadowCameraFov;

	light.shadowCameraVisible = this.shadowCameraVisible;

	light.shadowBias = this.shadowBias;
	light.shadowDarkness = this.shadowDarkness;

	light.shadowMapWidth = this.shadowMapWidth;
	light.shadowMapHeight = this.shadowMapHeight;

	return light;

};

// File:src/loaders/Cache.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Cache = {

	files: {},

	add: function ( key, file ) {

		// console.log( 'THREE.Cache', 'Adding key:', key );

		this.files[ key ] = file;

	},

	get: function ( key ) {

		// console.log( 'THREE.Cache', 'Checking key:', key );

		return this.files[ key ];

	},

	remove: function ( key ) {

		delete this.files[ key ];

	},

	clear: function () {

		this.files = {}

	}

};

// File:src/loaders/Loader.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Loader = function ( showStatus ) {

	this.showStatus = showStatus;
	this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;

	this.imageLoader = new THREE.ImageLoader();

	this.onLoadStart = function () {};
	this.onLoadProgress = function () {};
	this.onLoadComplete = function () {};

};

THREE.Loader.prototype = {

	constructor: THREE.Loader,

	crossOrigin: undefined,

	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 / 1024 ).toFixed( 2 ) + ' KB';

		}

		this.statusDomElement.innerHTML = message;

	},

	extractUrlBase: function ( url ) {

		var parts = url.split( '/' );

		if ( parts.length === 1 ) return './';

		parts.pop();

		return parts.join( '/' ) + '/';

	},

	initMaterials: function ( materials, texturePath ) {

		var array = [];

		for ( var i = 0; i < materials.length; ++ i ) {

			array[ i ] = this.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 scope = this;

		function nearest_pow2( n ) {

			var l = Math.log( n ) / Math.LN2;
			return Math.pow( 2, Math.round(  l ) );

		}

		function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {

			var fullPath = texturePath + sourceFile;

			var texture;

			var loader = THREE.Loader.Handlers.get( fullPath );

			if ( loader !== null ) {

				texture = loader.load( fullPath );

			} else {

				texture = new THREE.Texture();

				loader = scope.imageLoader;
				loader.crossOrigin = scope.crossOrigin;
				loader.load( fullPath, function ( image ) {

					if ( THREE.Math.isPowerOfTwo( image.width ) === false ||
						 THREE.Math.isPowerOfTwo( image.height ) === false ) {

						var width = nearest_pow2( image.width );
						var height = nearest_pow2( image.height );

						var canvas = document.createElement( 'canvas' );
						canvas.width = width;
						canvas.height = height;

						var context = canvas.getContext( '2d' );
						context.drawImage( image, 0, 0, width, height );

						texture.image = canvas;

					} else {

						texture.image = image;

					}

					texture.needsUpdate = true;

				} );

			}

			texture.sourceFile = sourceFile;

			if ( repeat ) {

				texture.repeat.set( repeat[ 0 ], repeat[ 1 ] );

				if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
				if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;

			}

			if ( offset ) {

				texture.offset.set( offset[ 0 ], offset[ 1 ] );

			}

			if ( wrap ) {

				var wrapMap = {
					'repeat': THREE.RepeatWrapping,
					'mirror': THREE.MirroredRepeatWrapping
				}

				if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ];
				if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ];

			}

			if ( anisotropy ) {

				texture.anisotropy = anisotropy;

			}

			where[ name ] = texture;

		}

		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 ) {

			mpars.transparent = m.transparent;

		}

		if ( m.opacity !== undefined && m.opacity < 1.0 ) {

			mpars.transparent = true;

		}

		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.colorEmissive ) {

			mpars.emissive = rgb2hex( m.colorEmissive );

		}

		// modifiers

		if ( m.transparency !== undefined ) {

			console.warn( 'THREE.Loader: transparency has been renamed to opacity' );
			m.opacity = m.transparency;

		}

		if ( m.opacity !== undefined ) {

			mpars.opacity = m.opacity;

		}

		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.mapAlpha && texturePath ) {

			create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );

		}

		//

		if ( m.mapBumpScale ) {

			mpars.bumpScale = m.mapBumpScale;

		}

		if ( m.mapNormalFactor ) {

			mpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor );

		}

		var material = new THREE[ mtype ]( mpars );

		if ( m.DbgName !== undefined ) material.name = m.DbgName;

		return material;

	}

};

THREE.Loader.Handlers = {

	handlers: [],

	add: function ( regex, loader ) {

		this.handlers.push( regex, loader );

	},

	get: function ( file ) {

		for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) {

			var regex = this.handlers[ i ];
			var loader  = this.handlers[ i + 1 ];

			if ( regex.test( file ) ) {

				return loader;

			}

		}

		return null;

	}

};

// File:src/loaders/XHRLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.XHRLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.XHRLoader.prototype = {

	constructor: THREE.XHRLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			if ( onLoad ) onLoad( cached );
			return;

		}

		var request = new XMLHttpRequest();
		request.open( 'GET', url, true );

		request.addEventListener( 'load', function ( event ) {

			THREE.Cache.add( url, this.response );

			if ( onLoad ) onLoad( this.response );

			scope.manager.itemEnd( url );

		}, false );

		if ( onProgress !== undefined ) {

			request.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		if ( onError !== undefined ) {

			request.addEventListener( 'error', function ( event ) {

				onError( event );

			}, false );

		}

		if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin;
		if ( this.responseType !== undefined ) request.responseType = this.responseType;

		request.send( null );

		scope.manager.itemStart( url );

	},

	setResponseType: function ( value ) {

		this.responseType = value;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	}

};

// File:src/loaders/ImageLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.ImageLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.ImageLoader.prototype = {

	constructor: THREE.ImageLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			onLoad( cached );
			return;

		}

		var image = document.createElement( 'img' );

		image.addEventListener( 'load', function ( event ) {

			THREE.Cache.add( url, this );

			if ( onLoad ) onLoad( this );
			
			scope.manager.itemEnd( url );

		}, false );

		if ( onProgress !== undefined ) {

			image.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		if ( onError !== undefined ) {

			image.addEventListener( 'error', function ( event ) {

				onError( event );

			}, false );

		}

		if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;

		image.src = url;

		scope.manager.itemStart( url );

		return image;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	}

}

// File:src/loaders/JSONLoader.js

/**
 * @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.constructor = THREE.JSONLoader;

THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {

	// 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 metadata = json.metadata;

					if ( metadata !== undefined ) {

						if ( metadata.type === 'object' ) {

							THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
							return;

						}

						if ( metadata.type === 'scene' ) {

							THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' );
							return;

						}

					}

					var result = context.parse( json, texturePath );
					callback( result.geometry, result.materials );

				} else {

					THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file 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 {

				THREE.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 geometry = new THREE.Geometry(),
	scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;

	parseModel( scale );

	parseSkin();
	parseMorphing( scale );

	geometry.computeFaceNormals();
	geometry.computeBoundingSphere();

	function parseModel( scale ) {

		function isBitSet( value, position ) {

			return value & ( 1 << position );

		}

		var i, j, fi,

		offset, zLength,

		colorIndex, normalIndex, uvIndex, materialIndex,

		type,
		isQuad,
		hasMaterial,
		hasFaceVertexUv,
		hasFaceNormal, hasFaceVertexNormal,
		hasFaceColor, hasFaceVertexColor,

		vertex, face, faceA, faceB, hex, normal,

		uvLayer, uv, u, v,

		faces = json.faces,
		vertices = json.vertices,
		normals = json.normals,
		colors = json.colors,

		nUvLayers = 0;

		if ( json.uvs !== undefined ) {

			// disregard empty arrays

			for ( i = 0; i < json.uvs.length; i ++ ) {

				if ( json.uvs[ i ].length ) nUvLayers ++;

			}

			for ( i = 0; i < nUvLayers; 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 );
			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, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);

			if ( isQuad ) {

				faceA = new THREE.Face3();
				faceA.a = faces[ offset ];
				faceA.b = faces[ offset + 1 ];
				faceA.c = faces[ offset + 3 ];

				faceB = new THREE.Face3();
				faceB.a = faces[ offset + 1 ];
				faceB.b = faces[ offset + 2 ];
				faceB.c = faces[ offset + 3 ];

				offset += 4;

				if ( hasMaterial ) {

					materialIndex = faces[ offset ++ ];
					faceA.materialIndex = materialIndex;
					faceB.materialIndex = materialIndex;

				}

				// to get face <=> uv index correspondence

				fi = geometry.faces.length;

				if ( hasFaceVertexUv ) {

					for ( i = 0; i < nUvLayers; i ++ ) {

						uvLayer = json.uvs[ i ];

						geometry.faceVertexUvs[ i ][ fi ] = [];
						geometry.faceVertexUvs[ i ][ fi + 1 ] = []

						for ( j = 0; j < 4; j ++ ) {

							uvIndex = faces[ offset ++ ];

							u = uvLayer[ uvIndex * 2 ];
							v = uvLayer[ uvIndex * 2 + 1 ];

							uv = new THREE.Vector2( u, v );

							if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
							if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );

						}

					}

				}

				if ( hasFaceNormal ) {

					normalIndex = faces[ offset ++ ] * 3;

					faceA.normal.set(
						normals[ normalIndex ++ ],
						normals[ normalIndex ++ ],
						normals[ normalIndex ]
					);

					faceB.normal.copy( faceA.normal );

				}

				if ( hasFaceVertexNormal ) {

					for ( i = 0; i < 4; i ++ ) {

						normalIndex = faces[ offset ++ ] * 3;

						normal = new THREE.Vector3(
							normals[ normalIndex ++ ],
							normals[ normalIndex ++ ],
							normals[ normalIndex ]
						);


						if ( i !== 2 ) faceA.vertexNormals.push( normal );
						if ( i !== 0 ) faceB.vertexNormals.push( normal );

					}

				}


				if ( hasFaceColor ) {

					colorIndex = faces[ offset ++ ];
					hex = colors[ colorIndex ];

					faceA.color.setHex( hex );
					faceB.color.setHex( hex );

				}


				if ( hasFaceVertexColor ) {

					for ( i = 0; i < 4; i ++ ) {

						colorIndex = faces[ offset ++ ];
						hex = colors[ colorIndex ];

						if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
						if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );

					}

				}

				geometry.faces.push( faceA );
				geometry.faces.push( faceB );

			} else {

				face = new THREE.Face3();
				face.a = faces[ offset ++ ];
				face.b = faces[ offset ++ ];
				face.c = faces[ offset ++ ];

				if ( hasMaterial ) {

					materialIndex = faces[ offset ++ ];
					face.materialIndex = materialIndex;

				}

				// to get face <=> uv index correspondence

				fi = geometry.faces.length;

				if ( hasFaceVertexUv ) {

					for ( i = 0; i < nUvLayers; i ++ ) {

						uvLayer = json.uvs[ i ];

						geometry.faceVertexUvs[ i ][ fi ] = [];

						for ( j = 0; j < 3; j ++ ) {

							uvIndex = faces[ offset ++ ];

							u = uvLayer[ uvIndex * 2 ];
							v = uvLayer[ uvIndex * 2 + 1 ];

							uv = new THREE.Vector2( u, v );

							geometry.faceVertexUvs[ i ][ fi ].push( uv );

						}

					}

				}

				if ( hasFaceNormal ) {

					normalIndex = faces[ offset ++ ] * 3;

					face.normal.set(
						normals[ normalIndex ++ ],
						normals[ normalIndex ++ ],
						normals[ normalIndex ]
					);

				}

				if ( hasFaceVertexNormal ) {

					for ( i = 0; i < 3; i ++ ) {

						normalIndex = faces[ offset ++ ] * 3;

						normal = new THREE.Vector3(
							normals[ normalIndex ++ ],
							normals[ normalIndex ++ ],
							normals[ normalIndex ]
						);

						face.vertexNormals.push( normal );

					}

				}


				if ( hasFaceColor ) {

					colorIndex = faces[ offset ++ ];
					face.color.setHex( colors[ colorIndex ] );

				}


				if ( hasFaceVertexColor ) {

					for ( i = 0; i < 3; i ++ ) {

						colorIndex = faces[ offset ++ ];
						face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );

					}

				}

				geometry.faces.push( face );

			}

		}

	};

	function parseSkin() {
		var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;

		if ( json.skinWeights ) {

			for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {

				var x =                               json.skinWeights[ i     ];
				var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
				var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
				var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;

				geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );

			}

		}

		if ( json.skinIndices ) {

			for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {

				var a =                               json.skinIndices[ i     ];
				var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
				var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
				var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;

				geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );

			}

		}

		geometry.bones = json.bones;

		if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {

			THREE.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
					geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );

		}


		// could change this to json.animations[0] or remove completely

		geometry.animation = json.animation;
		geometry.animations = json.animations;

	};

	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 || json.materials.length === 0 ) {

		return { geometry: geometry };

	} else {

		var materials = this.initMaterials( json.materials, texturePath );

		if ( this.needsTangents( materials ) ) {

			geometry.computeTangents();

		}

		return { geometry: geometry, materials: materials };

	}

};

// File:src/loaders/LoadingManager.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.LoadingManager = function ( onLoad, onProgress, onError ) {

	var scope = this;

	var loaded = 0, total = 0;

	this.onLoad = onLoad;
	this.onProgress = onProgress;
	this.onError = onError;

	this.itemStart = function ( url ) {

		total ++;

	};

	this.itemEnd = function ( url ) {

		loaded ++;

		if ( scope.onProgress !== undefined ) {

			scope.onProgress( url, loaded, total );

		}

		if ( loaded === total && scope.onLoad !== undefined ) {

			scope.onLoad();

		}

	};

};

THREE.DefaultLoadingManager = new THREE.LoadingManager();

// File:src/loaders/BufferGeometryLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.BufferGeometryLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.BufferGeometryLoader.prototype = {

	constructor: THREE.BufferGeometryLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var loader = new THREE.XHRLoader( scope.manager );
		loader.setCrossOrigin( this.crossOrigin );
		loader.load( url, function ( text ) {

			onLoad( scope.parse( JSON.parse( text ) ) );

		}, onProgress, onError );

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	},

	parse: function ( json ) {

		var geometry = new THREE.BufferGeometry();

		var attributes = json.data.attributes;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];
			var typedArray = new self[ attribute.type ]( attribute.array );

			geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) );

		}

		var offsets = json.data.offsets;

		if ( offsets !== undefined ) {

			geometry.offsets = JSON.parse( JSON.stringify( offsets ) );

		}

		var boundingSphere = json.data.boundingSphere;

		if ( boundingSphere !== undefined ) {

			var center = new THREE.Vector3();

			if ( boundingSphere.center !== undefined ) {

				center.fromArray( boundingSphere.center );

			}

			geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius );

		}

		return geometry;

	}

};

// File:src/loaders/MaterialLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.MaterialLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.MaterialLoader.prototype = {

	constructor: THREE.MaterialLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var loader = new THREE.XHRLoader( scope.manager );
		loader.setCrossOrigin( this.crossOrigin );
		loader.load( url, function ( text ) {

			onLoad( scope.parse( JSON.parse( text ) ) );

		}, onProgress, onError );

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	},

	parse: function ( json ) {

		var material = new THREE[ json.type ];

		if ( json.color !== undefined ) material.color.setHex( json.color );
		if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
		if ( json.specular !== undefined ) material.specular.setHex( json.specular );
		if ( json.shininess !== undefined ) material.shininess = json.shininess;
		if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
		if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
		if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
		if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
		if ( json.shading !== undefined ) material.shading = json.shading;
		if ( json.blending !== undefined ) material.blending = json.blending;
		if ( json.side !== undefined ) material.side = json.side;
		if ( json.opacity !== undefined ) material.opacity = json.opacity;
		if ( json.transparent !== undefined ) material.transparent = json.transparent;
		if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;

		// for PointCloudMaterial
		if ( json.size !== undefined ) material.size = json.size;
		if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;

		if ( json.materials !== undefined ) {

			for ( var i = 0, l = json.materials.length; i < l; i ++ ) {

				material.materials.push( this.parse( json.materials[ i ] ) );

			}

		}

		return material;

	}

};

// File:src/loaders/ObjectLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.ObjectLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
	this.texturePath = '';

};

THREE.ObjectLoader.prototype = {

	constructor: THREE.ObjectLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		if ( this.texturePath === '' ) {

			this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );

		}

		var scope = this;

		var loader = new THREE.XHRLoader( scope.manager );
		loader.setCrossOrigin( this.crossOrigin );
		loader.load( url, function ( text ) {

			scope.parse( JSON.parse( text ), onLoad );

		}, onProgress, onError );

	},

	setTexturePath: function ( value ) {

		this.texturePath = value;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	},

	parse: function ( json, onLoad ) {

		var geometries = this.parseGeometries( json.geometries );

		var images = this.parseImages( json.images, function () {

			if ( onLoad !== undefined ) onLoad( object );

		} );
		var textures  = this.parseTextures( json.textures, images );
		var materials = this.parseMaterials( json.materials, textures );
		var object = this.parseObject( json.object, geometries, materials );

		if ( json.images === undefined || json.images.length === 0 ) {

			if ( onLoad !== undefined ) onLoad( object );

		}

		return object;

	},

	parseGeometries: function ( json ) {

		var geometries = {};

		if ( json !== undefined ) {

			var geometryLoader = new THREE.JSONLoader();
			var bufferGeometryLoader = new THREE.BufferGeometryLoader();

			for ( var i = 0, l = json.length; i < l; i ++ ) {

				var geometry;
				var data = json[ i ];

				switch ( data.type ) {

					case 'PlaneGeometry':
					case 'PlaneBufferGeometry':

						geometry = new THREE[ data.type ](
							data.width,
							data.height,
							data.widthSegments,
							data.heightSegments
						);

						break;

					case 'BoxGeometry':
					case 'CubeGeometry': // backwards compatible

						geometry = new THREE.BoxGeometry(
							data.width,
							data.height,
							data.depth,
							data.widthSegments,
							data.heightSegments,
							data.depthSegments
						);

						break;

					case 'CircleGeometry':

						geometry = new THREE.CircleGeometry(
							data.radius,
							data.segments
						);

						break;

					case 'CylinderGeometry':

						geometry = new THREE.CylinderGeometry(
							data.radiusTop,
							data.radiusBottom,
							data.height,
							data.radialSegments,
							data.heightSegments,
							data.openEnded
						);

						break;

					case 'SphereGeometry':

						geometry = new THREE.SphereGeometry(
							data.radius,
							data.widthSegments,
							data.heightSegments,
							data.phiStart,
							data.phiLength,
							data.thetaStart,
							data.thetaLength
						);

						break;

					case 'IcosahedronGeometry':

						geometry = new THREE.IcosahedronGeometry(
							data.radius,
							data.detail
						);

						break;

					case 'TorusGeometry':

						geometry = new THREE.TorusGeometry(
							data.radius,
							data.tube,
							data.radialSegments,
							data.tubularSegments,
							data.arc
						);

						break;

					case 'TorusKnotGeometry':

						geometry = new THREE.TorusKnotGeometry(
							data.radius,
							data.tube,
							data.radialSegments,
							data.tubularSegments,
							data.p,
							data.q,
							data.heightScale
						);

						break;

					case 'BufferGeometry':

						geometry = bufferGeometryLoader.parse( data );

						break;

					case 'Geometry':

						geometry = geometryLoader.parse( data.data ).geometry;

						break;

				}

				geometry.uuid = data.uuid;

				if ( data.name !== undefined ) geometry.name = data.name;

				geometries[ data.uuid ] = geometry;

			}

		}

		return geometries;

	},

	parseMaterials: function ( json, textures ) {

		var materials = {};

		if ( json !== undefined ) {

			var getTexture = function ( name ) {

				if ( textures[ name ] === undefined ) {

					THREE.warn( 'THREE.ObjectLoader: Undefined texture', name );

				}

				return textures[ name ];

			};

			var loader = new THREE.MaterialLoader();

			for ( var i = 0, l = json.length; i < l; i ++ ) {

				var data = json[ i ];
				var material = loader.parse( data );

				material.uuid = data.uuid;

				if ( data.name !== undefined ) material.name = data.name;

				if ( data.map !== undefined ) {

					material.map = getTexture( data.map );

				}

				if ( data.bumpMap !== undefined ) {

					material.bumpMap = getTexture( data.bumpMap );
					if ( data.bumpScale ) {
						material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale );
					}

				}

				if ( data.alphaMap !== undefined ) {

					material.alphaMap = getTexture( data.alphaMap );

				}

				if ( data.envMap !== undefined ) {

					material.envMap = getTexture( data.envMap );

				}

				if ( data.normalMap !== undefined ) {

					material.normalMap = getTexture( data.normalMap );
					if ( data.normalScale ) {
						material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale );
					}

				}

				if ( data.lightMap !== undefined ) {

					material.lightMap = getTexture( data.lightMap );

				}

				if ( data.specularMap !== undefined ) {

					material.specularMap = getTexture( data.specularMap );

				}

				materials[ data.uuid ] = material;

			}

		}

		return materials;

	},

	parseImages: function ( json, onLoad ) {

		var scope = this;
		var images = {};

		if ( json !== undefined && json.length > 0 ) {

			var manager = new THREE.LoadingManager( onLoad );

			var loader = new THREE.ImageLoader( manager );
			loader.setCrossOrigin( this.crossOrigin );

			var loadImage = function ( url ) {

				scope.manager.itemStart( url );

				return loader.load( url, function () {

					scope.manager.itemEnd( url );

				} );

			};

			for ( var i = 0, l = json.length; i < l; i ++ ) {

				var image = json[ i ];
				var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;

				images[ image.uuid ] = loadImage( path );

			}

		}

		return images;

	},

	parseTextures: function ( json, images ) {

		var textures = {};

		if ( json !== undefined ) {

			for ( var i = 0, l = json.length; i < l; i ++ ) {

				var data = json[ i ];

				if ( data.image === undefined ) {

					THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid );

				}

				if ( images[ data.image ] === undefined ) {

					THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image );

				}

				var texture = new THREE.Texture( images[ data.image ] );
				texture.needsUpdate = true;

				texture.uuid = data.uuid;

				if ( data.name !== undefined ) texture.name = data.name;
				if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] );
				if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ];
				if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ];
				if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
				if ( data.wrap instanceof Array ) {

					texture.wrapS = THREE[ data.wrap[ 0 ] ];
					texture.wrapT = THREE[ data.wrap[ 1 ] ];

				}

				textures[ data.uuid ] = texture;

			}

		}

		return textures;

	},

	parseObject: function () {

		var matrix = new THREE.Matrix4();

		return function ( data, geometries, materials ) {

			var object;

			var getGeometry = function ( name ) {

				if ( geometries[ name ] === undefined ) {

					THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name );

				}

				return geometries[ name ];

			};

			var getMaterial = function ( name ) {

				if ( materials[ name ] === undefined ) {

					THREE.warn( 'THREE.ObjectLoader: Undefined material', name );

				}

				return materials[ name ];

			};

			switch ( data.type ) {

				case 'Scene':

					object = new THREE.Scene();

					break;

				case 'PerspectiveCamera':

					object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far );

					break;

				case 'OrthographicCamera':

					object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );

					break;

				case 'AmbientLight':

					object = new THREE.AmbientLight( data.color );

					break;

				case 'DirectionalLight':

					object = new THREE.DirectionalLight( data.color, data.intensity );

					break;

				case 'PointLight':

					object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay );

					break;

				case 'SpotLight':

					object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay );

					break;

				case 'HemisphereLight':

					object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity );

					break;

				case 'Mesh':

					object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) );

					break;

				case 'Line':

					object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );

					break;

				case 'PointCloud':

					object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) );

					break;

				case 'Sprite':

					object = new THREE.Sprite( getMaterial( data.material ) );

					break;

				case 'Group':

					object = new THREE.Group();

					break;

				default:

					object = new THREE.Object3D();

			}

			object.uuid = data.uuid;

			if ( data.name !== undefined ) object.name = data.name;
			if ( data.matrix !== undefined ) {

				matrix.fromArray( data.matrix );
				matrix.decompose( object.position, object.quaternion, object.scale );

			} else {

				if ( data.position !== undefined ) object.position.fromArray( data.position );
				if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
				if ( data.scale !== undefined ) object.scale.fromArray( data.scale );

			}

			if ( data.visible !== undefined ) object.visible = data.visible;
			if ( data.userData !== undefined ) object.userData = data.userData;

			if ( data.children !== undefined ) {

				for ( var child in data.children ) {

					object.add( this.parseObject( data.children[ child ], geometries, materials ) );

				}

			}

			return object;

		}

	}()

};

// File:src/loaders/TextureLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.TextureLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.TextureLoader.prototype = {

	constructor: THREE.TextureLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var loader = new THREE.ImageLoader( scope.manager );
		loader.setCrossOrigin( this.crossOrigin );
		loader.load( url, function ( image ) {

			var texture = new THREE.Texture( image );
			texture.needsUpdate = true;

			if ( onLoad !== undefined ) {

				onLoad( texture );

			}

		}, onProgress, onError );

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	}

};

// File:src/loaders/BinaryTextureLoader.js

/**
 * @author Nikos M. / https://github.com/foo123/
 *
 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
 */

THREE.DataTextureLoader = THREE.BinaryTextureLoader = function () {

	// override in sub classes
	this._parser = null;

};

THREE.BinaryTextureLoader.prototype = {

	constructor: THREE.BinaryTextureLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var texture = new THREE.DataTexture( );

		var loader = new THREE.XHRLoader();
		loader.setResponseType( 'arraybuffer' );

		loader.load( url, function ( buffer ) {

			var texData = scope._parser( buffer );

			if ( !texData ) return;

			if ( undefined !== texData.image ) {

				texture.image = texData.image;

			} else if ( undefined !== texData.data ) {

				texture.image.width = texData.width;
				texture.image.height = texData.height;
				texture.image.data = texData.data;

			}

			texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping;
			texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping;

			texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter;
			texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter;

			texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;

			if ( undefined !== texData.format ) {

				texture.format = texData.format;

			}
			if ( undefined !== texData.type ) {

				texture.type = texData.type;

			}

			if ( undefined !== texData.mipmaps ) {

				texture.mipmaps = texData.mipmaps;

			}

			if ( 1 === texData.mipmapCount ) {

				texture.minFilter = THREE.LinearFilter;

			}

			texture.needsUpdate = true;

			if ( onLoad ) onLoad( texture, texData );

		}, onProgress, onError );


		return texture;

	}

};

// File:src/loaders/CompressedTextureLoader.js

/**
 * @author mrdoob / http://mrdoob.com/
 *
 * Abstract Base class to block based textures loader (dds, pvr, ...)
 */

THREE.CompressedTextureLoader = function () {

	// override in sub classes
	this._parser = null;

};


THREE.CompressedTextureLoader.prototype = {

	constructor: THREE.CompressedTextureLoader,

	load: function ( url, onLoad, onError ) {

		var scope = this;

		var images = [];

		var texture = new THREE.CompressedTexture();
		texture.image = images;

		var loader = new THREE.XHRLoader();
		loader.setResponseType( 'arraybuffer' );

		if ( url instanceof Array ) {

			var loaded = 0;

			var loadTexture = function ( i ) {

				loader.load( url[ i ], function ( buffer ) {

					var texDatas = scope._parser( buffer, true );

					images[ i ] = {
						width: texDatas.width,
						height: texDatas.height,
						format: texDatas.format,
						mipmaps: texDatas.mipmaps
					};

					loaded += 1;

					if ( loaded === 6 ) {

						if (texDatas.mipmapCount == 1)
 							texture.minFilter = THREE.LinearFilter;

						texture.format = texDatas.format;
						texture.needsUpdate = true;

						if ( onLoad ) onLoad( texture );

					}

				} );

			};

			for ( var i = 0, il = url.length; i < il; ++ i ) {

				loadTexture( i );

			}

		} else {

			// compressed cubemap texture stored in a single DDS file

			loader.load( url, function ( buffer ) {

				var texDatas = scope._parser( buffer, true );

				if ( texDatas.isCubemap ) {

					var faces = texDatas.mipmaps.length / texDatas.mipmapCount;

					for ( var f = 0; f < faces; f ++ ) {

						images[ f ] = { mipmaps : [] };

						for ( var i = 0; i < texDatas.mipmapCount; i ++ ) {

							images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
							images[ f ].format = texDatas.format;
							images[ f ].width = texDatas.width;
							images[ f ].height = texDatas.height;

						}

					}

				} else {

					texture.image.width = texDatas.width;
					texture.image.height = texDatas.height;
					texture.mipmaps = texDatas.mipmaps;

				}

				if ( texDatas.mipmapCount === 1 ) {

					texture.minFilter = THREE.LinearFilter;

				}

				texture.format = texDatas.format;
				texture.needsUpdate = true;

				if ( onLoad ) onLoad( texture );

			} );

		}

		return texture;

	}

};

// File:src/materials/Material.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

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 = false;

	this.blending = THREE.NormalBlending;

	this.blendSrc = THREE.SrcAlphaFactor;
	this.blendDst = THREE.OneMinusSrcAlphaFactor;
	this.blendEquation = THREE.AddEquation;
	this.blendSrcAlpha = null;
	this.blendDstAlpha = null;
	this.blendEquationAlpha = null;

	this.depthTest = true;
	this.depthWrite = true;

	this.colorWrite = true;

	this.polygonOffset = false;
	this.polygonOffsetFactor = 0;
	this.polygonOffsetUnits = 0;

	this.alphaTest = 0;

	this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer

	this.visible = true;

	this._needsUpdate = true;

};

THREE.Material.prototype = {

	constructor: THREE.Material,

	get needsUpdate () {

		return this._needsUpdate;

	},

	set needsUpdate ( value ) {

		if ( value === true ) this.update();

		this._needsUpdate = value;

	},

	setValues: function ( values ) {

		if ( values === undefined ) return;

		for ( var key in values ) {

			var newValue = values[ key ];

			if ( newValue === undefined ) {

				THREE.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 if ( key == 'overdraw' ) {

					// ensure overdraw is backwards-compatable with legacy boolean type
					this[ key ] = Number( newValue );

				} else {

					this[ key ] = newValue;

				}

			}

		}

	},

	toJSON: function () {

		var output = {
			metadata: {
				version: 4.2,
				type: 'material',
				generator: 'MaterialExporter'
			},
			uuid: this.uuid,
			type: this.type
		};

		if ( this.name !== "" ) output.name = this.name;

		if ( this instanceof THREE.MeshBasicMaterial ) {

			output.color = this.color.getHex();
			if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
			if ( this.side !== THREE.FrontSide ) output.side = this.side;

		} else if ( this instanceof THREE.MeshLambertMaterial ) {

			output.color = this.color.getHex();
			output.emissive = this.emissive.getHex();
			if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
			if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading;
			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
			if ( this.side !== THREE.FrontSide ) output.side = this.side;

		} else if ( this instanceof THREE.MeshPhongMaterial ) {

			output.color = this.color.getHex();
			output.emissive = this.emissive.getHex();
			output.specular = this.specular.getHex();
			output.shininess = this.shininess;
			if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
			if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading;
			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
			if ( this.side !== THREE.FrontSide ) output.side = this.side;

		} else if ( this instanceof THREE.MeshNormalMaterial ) {

			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
			if ( this.side !== THREE.FrontSide ) output.side = this.side;

		} else if ( this instanceof THREE.MeshDepthMaterial ) {

			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
			if ( this.side !== THREE.FrontSide ) output.side = this.side;

		} else if ( this instanceof THREE.PointCloudMaterial ) {

			output.size  = this.size;
			output.sizeAttenuation = this.sizeAttenuation;
			output.color = this.color.getHex();

			if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
			if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;

		} else if ( this instanceof THREE.ShaderMaterial ) {

			output.uniforms = this.uniforms;
			output.vertexShader = this.vertexShader;
			output.fragmentShader = this.fragmentShader;

		} else if ( this instanceof THREE.SpriteMaterial ) {

			output.color = this.color.getHex();

		}

		if ( this.opacity < 1 ) output.opacity = this.opacity;
		if ( this.transparent !== false ) output.transparent = this.transparent;
		if ( this.wireframe !== false ) output.wireframe = this.wireframe;

		return output;

	},

	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.blendSrcAlpha = this.blendSrcAlpha;
		material.blendDstAlpha = this.blendDstAlpha;
		material.blendEquationAlpha = this.blendEquationAlpha;

		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;

	},

	update: function () {

		this.dispatchEvent( { type: 'update' } );

	},

	dispose: function () {

		this.dispatchEvent( { type: 'dispose' } );

	}

};

THREE.EventDispatcher.prototype.apply( THREE.Material.prototype );

THREE.MaterialIdCount = 0;

// File:src/materials/LineBasicMaterial.js

/**
 * @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.type = 'LineBasicMaterial';

	this.color = new THREE.Color( 0xffffff );

	this.linewidth = 1;
	this.linecap = 'round';
	this.linejoin = 'round';

	this.vertexColors = THREE.NoColors;

	this.fog = true;

	this.setValues( parameters );

};

THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial;

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;

};

// File:src/materials/LineDashedMaterial.js

/**
 * @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.type = 'LineDashedMaterial';

	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.constructor = THREE.LineDashedMaterial;

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;

};

// File:src/materials/MeshBasicMaterial.js

/**
 * @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> ),
 *
 *  alphaMap: 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.type = 'MeshBasicMaterial';

	this.color = new THREE.Color( 0xffffff ); // emissive

	this.map = null;

	this.lightMap = null;

	this.specularMap = null;

	this.alphaMap = 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.constructor = THREE.MeshBasicMaterial;

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.alphaMap = this.alphaMap;

	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;

};

// File:src/materials/MeshLambertMaterial.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  emissive: <hex>,
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *
 *  specularMap: new THREE.Texture( <Image> ),
 *
 *  alphaMap: 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.type = 'MeshLambertMaterial';

	this.color = new THREE.Color( 0xffffff ); // diffuse
	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.alphaMap = 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.constructor = THREE.MeshLambertMaterial;

THREE.MeshLambertMaterial.prototype.clone = function () {

	var material = new THREE.MeshLambertMaterial();

	THREE.Material.prototype.clone.call( this, material );

	material.color.copy( this.color );
	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.alphaMap = this.alphaMap;

	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;

};

// File:src/materials/MeshPhongMaterial.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <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> ),
 *
 *  alphaMap: 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.type = 'MeshPhongMaterial';

	this.color = new THREE.Color( 0xffffff ); // diffuse
	this.emissive = new THREE.Color( 0x000000 );
	this.specular = new THREE.Color( 0x111111 );
	this.shininess = 30;

	this.metal = false;

	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.alphaMap = 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.constructor = THREE.MeshPhongMaterial;

THREE.MeshPhongMaterial.prototype.clone = function () {

	var material = new THREE.MeshPhongMaterial();

	THREE.Material.prototype.clone.call( this, material );

	material.color.copy( this.color );
	material.emissive.copy( this.emissive );
	material.specular.copy( this.specular );
	material.shininess = this.shininess;

	material.metal = this.metal;

	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.alphaMap = this.alphaMap;

	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;

};

// File:src/materials/MeshDepthMaterial.js

/**
 * @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.type = 'MeshDepthMaterial';

	this.morphTargets = false;
	this.wireframe = false;
	this.wireframeLinewidth = 1;

	this.setValues( parameters );

};

THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial;

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;

};

// File:src/materials/MeshNormalMaterial.js

/**
 * @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.type = 'MeshNormalMaterial';

	this.wireframe = false;
	this.wireframeLinewidth = 1;

	this.morphTargets = false;

	this.setValues( parameters );

};

THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial;

THREE.MeshNormalMaterial.prototype.clone = function () {

	var material = new THREE.MeshNormalMaterial();

	THREE.Material.prototype.clone.call( this, material );

	material.wireframe = this.wireframe;
	material.wireframeLinewidth = this.wireframeLinewidth;

	return material;

};

// File:src/materials/MeshFaceMaterial.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.MeshFaceMaterial = function ( materials ) {

	this.uuid = THREE.Math.generateUUID();

	this.type = 'MeshFaceMaterial';
	
	this.materials = materials instanceof Array ? materials : [];

};

THREE.MeshFaceMaterial.prototype = {

	constructor: THREE.MeshFaceMaterial,

	toJSON: function () {

		var output = {
			metadata: {
				version: 4.2,
				type: 'material',
				generator: 'MaterialExporter'
			},
			uuid: this.uuid,
			type: this.type,
			materials: []
		};

		for ( var i = 0, l = this.materials.length; i < l; i ++ ) {

			output.materials.push( this.materials[ i ].toJSON() );

		}

		return output;

	},

	clone: function () {

		var material = new THREE.MeshFaceMaterial();

		for ( var i = 0; i < this.materials.length; i ++ ) {

			material.materials.push( this.materials[ i ].clone() );

		}

		return material;

	}

};

// File:src/materials/PointCloudMaterial.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  size: <float>,
 *  sizeAttenuation: <bool>,
 *
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *  depthWrite: <bool>,
 *
 *  vertexColors: <bool>,
 *
 *  fog: <bool>
 * }
 */

THREE.PointCloudMaterial = function ( parameters ) {

	THREE.Material.call( this );

	this.type = 'PointCloudMaterial';

	this.color = new THREE.Color( 0xffffff );

	this.map = null;

	this.size = 1;
	this.sizeAttenuation = true;

	this.vertexColors = THREE.NoColors;

	this.fog = true;

	this.setValues( parameters );

};

THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial;

THREE.PointCloudMaterial.prototype.clone = function () {

	var material = new THREE.PointCloudMaterial();

	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;

};

// backwards compatibility

THREE.ParticleBasicMaterial = function ( parameters ) {

	THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' );
	return new THREE.PointCloudMaterial( parameters );

};

THREE.ParticleSystemMaterial = function ( parameters ) {

	THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' );
	return new THREE.PointCloudMaterial( parameters );

};

// File:src/materials/ShaderMaterial.js

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  defines: { "label" : "value" },
 *  uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
 *
 *  fragmentShader: <string>,
 *  vertexShader: <string>,
 *
 *  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.type = 'ShaderMaterial';

	this.defines = {};
	this.uniforms = {};
	this.attributes = null;

	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 = 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

	// When rendered geometry doesn't include these attributes but the material does,
	// use these default values in WebGL. This avoids errors when buffer data is missing.
	this.defaultAttributeValues = {
		'color': [ 1, 1, 1 ],
		'uv': [ 0, 0 ],
		'uv2': [ 0, 0 ]
	};

	this.index0AttributeName = undefined;

	this.setValues( parameters );

};

THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial;

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;

};

// File:src/materials/RawShaderMaterial.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RawShaderMaterial = function ( parameters ) {

	THREE.ShaderMaterial.call( this, parameters );

	this.type = 'RawShaderMaterial';

};

THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial;

THREE.RawShaderMaterial.prototype.clone = function () {

	var material = new THREE.RawShaderMaterial();

	THREE.ShaderMaterial.prototype.clone.call( this, material );

	return material;

};

// File:src/materials/SpriteMaterial.js

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *  depthWrite: <bool>,
 *
 *	uvOffset: new THREE.Vector2(),
 *	uvScale: new THREE.Vector2(),
 *
 *  fog: <bool>
 * }
 */

THREE.SpriteMaterial = function ( parameters ) {

	THREE.Material.call( this );

	this.type = 'SpriteMaterial';

	this.color = new THREE.Color( 0xffffff );
	this.map = null;

	this.rotation = 0;

	this.fog = false;

	// set parameters

	this.setValues( parameters );

};

THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial;

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.rotation = this.rotation;

	material.fog = this.fog;

	return material;

};

// File:src/textures/Texture.js

/**
 * @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 ) {

	Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } );

	this.uuid = THREE.Math.generateUUID();

	this.name = '';
	this.sourceFile = '';

	this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE;
	this.mipmaps = [];

	this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING;

	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.DEFAULT_IMAGE = undefined;
THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping;

THREE.Texture.prototype = {

	constructor: THREE.Texture,

	get needsUpdate () {

		return this._needsUpdate;

	},

	set needsUpdate ( value ) {

		if ( value === true ) this.update();

		this._needsUpdate = value;

	},

	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;

	},

	update: function () {

		this.dispatchEvent( { type: 'update' } );

	},

	dispose: function () {

		this.dispatchEvent( { type: 'dispose' } );

	}

};

THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype );

THREE.TextureIdCount = 0;

// File:src/textures/CubeTexture.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {

	mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping;
	
	THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

	this.images = images;

};

THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype );
THREE.CubeTexture.prototype.constructor = THREE.CubeTexture;

THREE.CubeTexture.clone = function ( texture ) {

	if ( texture === undefined ) texture = new THREE.CubeTexture();

	THREE.Texture.prototype.clone.call( this, texture );

	texture.images = this.images;

	return texture;

};

// File:src/textures/CompressedTexture.js

/**
 * @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;

	// no flipping for cube textures
	// (also flipping doesn't work for compressed textures )

	this.flipY = false;

	// can't generate mipmaps for compressed textures
	// mips must be embedded in DDS files

	this.generateMipmaps = false;

};

THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );
THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture;

THREE.CompressedTexture.prototype.clone = function () {

	var texture = new THREE.CompressedTexture();

	THREE.Texture.prototype.clone.call( this, texture );

	return texture;

};

// File:src/textures/DataTexture.js

/**
 * @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.constructor = THREE.DataTexture;

THREE.DataTexture.prototype.clone = function () {

	var texture = new THREE.DataTexture();

	THREE.Texture.prototype.clone.call( this, texture );

	return texture;

};

// File:src/textures/VideoTexture.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {

	THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

	this.generateMipmaps = false;

	var scope = this;

	var update = function () {

		requestAnimationFrame( update );

		if ( video.readyState === video.HAVE_ENOUGH_DATA ) {

			scope.needsUpdate = true;

		}

	};

	update();

};

THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype );
THREE.VideoTexture.prototype.constructor = THREE.VideoTexture;

// File:src/objects/Group.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Group = function () {

	THREE.Object3D.call( this );

	this.type = 'Group';

};

THREE.Group.prototype = Object.create( THREE.Object3D.prototype );
THREE.Group.prototype.constructor = THREE.Group;

// File:src/objects/PointCloud.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.PointCloud = function ( geometry, material ) {

	THREE.Object3D.call( this );

	this.type = 'PointCloud';

	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } );

};

THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype );
THREE.PointCloud.prototype.constructor = THREE.PointCloud;

THREE.PointCloud.prototype.raycast = ( function () {

	var inverseMatrix = new THREE.Matrix4();
	var ray = new THREE.Ray();

	return function ( raycaster, intersects ) {

		var object = this;
		var geometry = object.geometry;
		var threshold = raycaster.params.PointCloud.threshold;

		inverseMatrix.getInverse( this.matrixWorld );
		ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

		if ( geometry.boundingBox !== null ) {

			if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {

				return;

			}

		}

		var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
		var position = new THREE.Vector3();

		var testPoint = function ( point, index ) {

			var rayPointDistance = ray.distanceToPoint( point );

			if ( rayPointDistance < localThreshold ) {

				var intersectPoint = ray.closestPointToPoint( point );
				intersectPoint.applyMatrix4( object.matrixWorld );

				var distance = raycaster.ray.origin.distanceTo( intersectPoint );

				intersects.push( {

					distance: distance,
					distanceToRay: rayPointDistance,
					point: intersectPoint.clone(),
					index: index,
					face: null,
					object: object

				} );

			}

		};

		if ( geometry instanceof THREE.BufferGeometry ) {

			var attributes = geometry.attributes;
			var positions = attributes.position.array;

			if ( attributes.index !== undefined ) {

				var indices = attributes.index.array;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					var offset = {
						start: 0,
						count: indices.length,
						index: 0
					};

					offsets = [ offset ];

				}

				for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {

					var start = offsets[ oi ].start;
					var count = offsets[ oi ].count;
					var index = offsets[ oi ].index;

					for ( var i = start, il = start + count; i < il; i ++ ) {

						var a = index + indices[ i ];

						position.fromArray( positions, a * 3 );

						testPoint( position, a );

					}

				}

			} else {

				var pointCount = positions.length / 3;

				for ( var i = 0; i < pointCount; i ++ ) {

					position.set(
						positions[ 3 * i ],
						positions[ 3 * i + 1 ],
						positions[ 3 * i + 2 ]
					);

					testPoint( position, i );

				}

			}

		} else {

			var vertices = this.geometry.vertices;

			for ( var i = 0; i < vertices.length; i ++ ) {

				testPoint( vertices[ i ], i );

			}

		}

	};

}() );

THREE.PointCloud.prototype.clone = function ( object ) {

	if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material );

	THREE.Object3D.prototype.clone.call( this, object );

	return object;

};

// Backwards compatibility

THREE.ParticleSystem = function ( geometry, material ) {

	THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' );
	return new THREE.PointCloud( geometry, material );

};

// File:src/objects/Line.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Line = function ( geometry, material, mode ) {

	THREE.Object3D.call( this );

	this.type = 'Line';

	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );

	this.mode = mode !== undefined ? mode : THREE.LineStrip;

};

THREE.LineStrip = 0;
THREE.LinePieces = 1;

THREE.Line.prototype = Object.create( THREE.Object3D.prototype );
THREE.Line.prototype.constructor = THREE.Line;

THREE.Line.prototype.raycast = ( function () {

	var inverseMatrix = new THREE.Matrix4();
	var ray = new THREE.Ray();
	var sphere = new THREE.Sphere();

	return function ( raycaster, intersects ) {

		var precision = raycaster.linePrecision;
		var precisionSq = precision * precision;

		var geometry = this.geometry;

		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

		// Checking boundingSphere distance to ray

		sphere.copy( geometry.boundingSphere );
		sphere.applyMatrix4( this.matrixWorld );

		if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {

			return;

		}

		inverseMatrix.getInverse( this.matrixWorld );
		ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

		var vStart = new THREE.Vector3();
		var vEnd = new THREE.Vector3();
		var interSegment = new THREE.Vector3();
		var interRay = new THREE.Vector3();
		var step = this.mode === THREE.LineStrip ? 1 : 2;

		if ( geometry instanceof THREE.BufferGeometry ) {

			var attributes = geometry.attributes;

			if ( attributes.index !== undefined ) {

				var indices = attributes.index.array;
				var positions = attributes.position.array;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					offsets = [ { start: 0, count: indices.length, index: 0 } ];

				}

				for ( var oi = 0; oi < offsets.length; oi ++) {

					var start = offsets[ oi ].start;
					var count = offsets[ oi ].count;
					var index = offsets[ oi ].index;

					for ( var i = start; i < start + count - 1; i += step ) {

						var a = index + indices[ i ];
						var b = index + indices[ i + 1 ];

						vStart.fromArray( positions, a * 3 );
						vEnd.fromArray( positions, b * 3 );

						var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );

						if ( distSq > precisionSq ) continue;

						var distance = ray.origin.distanceTo( interRay );

						if ( distance < raycaster.near || distance > raycaster.far ) continue;

						intersects.push( {

							distance: distance,
							// What do we want? intersection point on the ray or on the segment??
							// point: raycaster.ray.at( distance ),
							point: interSegment.clone().applyMatrix4( this.matrixWorld ),
							index: i,
							offsetIndex: oi,
							face: null,
							faceIndex: null,
							object: this

						} );

					}

				}

			} else {

				var positions = attributes.position.array;

				for ( var i = 0; i < positions.length / 3 - 1; i += step ) {

					vStart.fromArray( positions, 3 * i );
					vEnd.fromArray( positions, 3 * i + 3 );

					var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );

					if ( distSq > precisionSq ) continue;

					var distance = ray.origin.distanceTo( interRay );

					if ( distance < raycaster.near || distance > raycaster.far ) continue;

					intersects.push( {

						distance: distance,
						// What do we want? intersection point on the ray or on the segment??
						// point: raycaster.ray.at( distance ),
						point: interSegment.clone().applyMatrix4( this.matrixWorld ),
						index: i,
						face: null,
						faceIndex: null,
						object: this

					} );

				}

			}

		} else if ( geometry instanceof THREE.Geometry ) {

			var vertices = geometry.vertices;
			var nbVertices = vertices.length;

			for ( var i = 0; i < nbVertices - 1; i += step ) {

				var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );

				if ( distSq > precisionSq ) continue;

				var distance = ray.origin.distanceTo( interRay );

				if ( distance < raycaster.near || distance > raycaster.far ) continue;

				intersects.push( {

					distance: distance,
					// What do we want? intersection point on the ray or on the segment??
					// point: raycaster.ray.at( distance ),
					point: interSegment.clone().applyMatrix4( this.matrixWorld ),
					index: i,
					face: null,
					faceIndex: null,
					object: this

				} );

			}

		}

	};

}() );

THREE.Line.prototype.clone = function ( object ) {

	if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode );

	THREE.Object3D.prototype.clone.call( this, object );

	return object;

};

// File:src/objects/Mesh.js

/**
 * @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.type = 'Mesh';
	
	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );

	this.updateMorphTargets();

};

THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
THREE.Mesh.prototype.constructor = THREE.Mesh;

THREE.Mesh.prototype.updateMorphTargets = function () {

	if ( this.geometry.morphTargets !== undefined && 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 ];

	}

	THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );

	return 0;

};


THREE.Mesh.prototype.raycast = ( function () {

	var inverseMatrix = new THREE.Matrix4();
	var ray = new THREE.Ray();
	var sphere = new THREE.Sphere();

	var vA = new THREE.Vector3();
	var vB = new THREE.Vector3();
	var vC = new THREE.Vector3();

	return function ( raycaster, intersects ) {

		var geometry = this.geometry;

		// Checking boundingSphere distance to ray

		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

		sphere.copy( geometry.boundingSphere );
		sphere.applyMatrix4( this.matrixWorld );

		if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {

			return;

		}

		// Check boundingBox before continuing

		inverseMatrix.getInverse( this.matrixWorld );
		ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

		if ( geometry.boundingBox !== null ) {

			if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {

				return;

			}

		}

		if ( geometry instanceof THREE.BufferGeometry ) {

			var material = this.material;

			if ( material === undefined ) return;

			var attributes = geometry.attributes;

			var a, b, c;
			var precision = raycaster.precision;

			if ( attributes.index !== undefined ) {

				var indices = attributes.index.array;
				var positions = attributes.position.array;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					offsets = [ { start: 0, count: indices.length, index: 0 } ];

				}

				for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {

					var start = offsets[ oi ].start;
					var count = offsets[ oi ].count;
					var index = offsets[ oi ].index;

					for ( var i = start, il = start + count; i < il; i += 3 ) {

						a = index + indices[ i ];
						b = index + indices[ i + 1 ];
						c = index + indices[ i + 2 ];

						vA.fromArray( positions, a * 3 );
						vB.fromArray( positions, b * 3 );
						vC.fromArray( positions, c * 3 );

						if ( material.side === THREE.BackSide ) {

							var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

						} else {

							var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

						}

						if ( intersectionPoint === null ) continue;

						intersectionPoint.applyMatrix4( this.matrixWorld );

						var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

						if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;

						intersects.push( {

							distance: distance,
							point: intersectionPoint,
							face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
							faceIndex: null,
							object: this

						} );

					}

				}

			} else {

				var positions = attributes.position.array;

				for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {

					a = i;
					b = i + 1;
					c = i + 2;

					vA.fromArray( positions, j );
					vB.fromArray( positions, j + 3 );
					vC.fromArray( positions, j + 6 );

					if ( material.side === THREE.BackSide ) {

						var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

					} else {

						var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

					}

					if ( intersectionPoint === null ) continue;

					intersectionPoint.applyMatrix4( this.matrixWorld );

					var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

					if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;

					intersects.push( {

						distance: distance,
						point: intersectionPoint,
						face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
						faceIndex: null,
						object: this

					} );

				}

			}

		} else if ( geometry instanceof THREE.Geometry ) {

			var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
			var objectMaterials = isFaceMaterial === true ? this.material.materials : null;

			var a, b, c;
			var precision = raycaster.precision;

			var vertices = geometry.vertices;

			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

				var face = geometry.faces[ f ];

				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;

				if ( material === undefined ) continue;

				a = vertices[ face.a ];
				b = vertices[ face.b ];
				c = vertices[ face.c ];

				if ( material.morphTargets === true ) {

					var morphTargets = geometry.morphTargets;
					var morphInfluences = this.morphTargetInfluences;

					vA.set( 0, 0, 0 );
					vB.set( 0, 0, 0 );
					vC.set( 0, 0, 0 );

					for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {

						var influence = morphInfluences[ t ];

						if ( influence === 0 ) continue;

						var targets = morphTargets[ t ].vertices;

						vA.x += ( targets[ face.a ].x - a.x ) * influence;
						vA.y += ( targets[ face.a ].y - a.y ) * influence;
						vA.z += ( targets[ face.a ].z - a.z ) * influence;

						vB.x += ( targets[ face.b ].x - b.x ) * influence;
						vB.y += ( targets[ face.b ].y - b.y ) * influence;
						vB.z += ( targets[ face.b ].z - b.z ) * influence;

						vC.x += ( targets[ face.c ].x - c.x ) * influence;
						vC.y += ( targets[ face.c ].y - c.y ) * influence;
						vC.z += ( targets[ face.c ].z - c.z ) * influence;

					}

					vA.add( a );
					vB.add( b );
					vC.add( c );

					a = vA;
					b = vB;
					c = vC;

				}

				if ( material.side === THREE.BackSide ) {

					var intersectionPoint = ray.intersectTriangle( c, b, a, true );

				} else {

					var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );

				}

				if ( intersectionPoint === null ) continue;

				intersectionPoint.applyMatrix4( this.matrixWorld );

				var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

				if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;

				intersects.push( {

					distance: distance,
					point: intersectionPoint,
					face: face,
					faceIndex: f,
					object: this

				} );

			}

		}

	};

}() );

THREE.Mesh.prototype.clone = function ( object, recursive ) {

	if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );

	THREE.Object3D.prototype.clone.call( this, object, recursive );

	return object;

};

// File:src/objects/Bone.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author ikerr / http://verold.com
 */

THREE.Bone = function ( skin ) {

	THREE.Object3D.call( this );

	this.type = 'Bone';

	this.skin = skin;

};

THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
THREE.Bone.prototype.constructor = THREE.Bone;

// File:src/objects/Skeleton.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author michael guerrero / http://realitymeltdown.com
 * @author ikerr / http://verold.com
 */

THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {

	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;

	this.identityMatrix = new THREE.Matrix4();

	// copy the bone array

	bones = bones || [];

	this.bones = bones.slice( 0 );

	// create a bone texture or an array of floats

	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 ( this.bones.length > 256 )
			size = 64;
		else if ( this.bones.length > 64 )
			size = 32;
		else if ( this.bones.length > 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 * this.bones.length );

	}

	// use the supplied bone inverses or calculate the inverses

	if ( boneInverses === undefined ) {

		this.calculateInverses();

	} else {

		if ( this.bones.length === boneInverses.length ) {

			this.boneInverses = boneInverses.slice( 0 );

		} else {

			THREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' );

			this.boneInverses = [];

			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

				this.boneInverses.push( new THREE.Matrix4() );

			}

		}

	}

};

THREE.Skeleton.prototype.calculateInverses = function () {

	this.boneInverses = [];

	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

		var inverse = new THREE.Matrix4();

		if ( this.bones[ b ] ) {

			inverse.getInverse( this.bones[ b ].matrixWorld );

		}

		this.boneInverses.push( inverse );

	}

};

THREE.Skeleton.prototype.pose = function () {

	var bone;

	// recover the bind-time world matrices

	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

		bone = this.bones[ b ];

		if ( bone ) {

			bone.matrixWorld.getInverse( this.boneInverses[ b ] );

		}

	}

	// compute the local matrices, positions, rotations and scales

	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

		bone = this.bones[ b ];

		if ( bone ) {

			if ( bone.parent ) {

				bone.matrix.getInverse( bone.parent.matrixWorld );
				bone.matrix.multiply( bone.matrixWorld );

			} else {

				bone.matrix.copy( bone.matrixWorld );

			}

			bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );

		}

	}

};

THREE.Skeleton.prototype.update = ( function () {

	var offsetMatrix = new THREE.Matrix4();
	
	return function () {

		// 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

			var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;

			offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
			offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );

		}

		if ( this.useVertexTexture ) {

			this.boneTexture.needsUpdate = true;

		}
		
	};

} )();


// File:src/objects/SkinnedMesh.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author ikerr / http://verold.com
 */

THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {

	THREE.Mesh.call( this, geometry, material );

	this.type = 'SkinnedMesh';

	this.bindMode = "attached";
	this.bindMatrix = new THREE.Matrix4();
	this.bindMatrixInverse = new THREE.Matrix4();

	// init bones

	// TODO: remove bone creation as there is no reason (other than
	// convenience) for THREE.SkinnedMesh to do this.

	var bones = [];

	if ( this.geometry && this.geometry.bones !== undefined ) {

		var bone, gbone, p, q, s;

		for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {

			gbone = this.geometry.bones[ b ];

			p = gbone.pos;
			q = gbone.rotq;
			s = gbone.scl;

			bone = new THREE.Bone( this );
			bones.push( bone );

			bone.name = gbone.name;
			bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );
			bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );

			if ( s !== undefined ) {

				bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );

			} else {

				bone.scale.set( 1, 1, 1 );

			}

		}

		for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {

			gbone = this.geometry.bones[ b ];

			if ( gbone.parent !== - 1 ) {

				bones[ gbone.parent ].add( bones[ b ] );

			} else {

				this.add( bones[ b ] );

			}

		}

	}

	this.normalizeSkinWeights();

	this.updateMatrixWorld( true );
	this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );

};


THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh;

THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {

	this.skeleton = skeleton;

	if ( bindMatrix === undefined ) {

		this.updateMatrixWorld( true );

		bindMatrix = this.matrixWorld;

	}

	this.bindMatrix.copy( bindMatrix );
	this.bindMatrixInverse.getInverse( bindMatrix );

};

THREE.SkinnedMesh.prototype.pose = function () {

	this.skeleton.pose();

};

THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {

	if ( this.geometry instanceof THREE.Geometry ) {

		for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {

			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

			}

		}

	} else {

		// skinning weights assumed to be normalized for THREE.BufferGeometry

	}

};

THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {

	THREE.Mesh.prototype.updateMatrixWorld.call( this, true );

	if ( this.bindMode === "attached" ) {

		this.bindMatrixInverse.getInverse( this.matrixWorld );

	} else if ( this.bindMode === "detached" ) {

		this.bindMatrixInverse.getInverse( this.bindMatrix );

	} else {

		THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );

	}

};

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;

};


// File:src/objects/MorphAnimMesh.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.MorphAnimMesh = function ( geometry, material ) {

	THREE.Mesh.call( this, geometry, material );

	this.type = 'MorphAnimMesh';

	// 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.constructor = THREE.MorphAnimMesh;

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 ];

			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 {

		THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' );

	}

};

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.interpolateTargets = function ( a, b, t ) {

	var influences = this.morphTargetInfluences;

	for ( var i = 0, l = influences.length; i < l; i ++ ) {

		influences[ i ] = 0;

	}

	if ( a > -1 ) influences[ a ] = 1 - t;
	if ( b > -1 ) influences[ b ] = t;

};

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;

};

// File:src/objects/LOD.js

/**
 * @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.constructor = THREE.LOD;

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.raycast = ( function () {

	var matrixPosition = new THREE.Vector3();

	return function ( raycaster, intersects ) {

		matrixPosition.setFromMatrixPosition( this.matrixWorld );

		var distance = raycaster.ray.origin.distanceTo( matrixPosition );

		this.getObjectForDistance( distance ).raycast( raycaster, intersects );

	};

}() );

THREE.LOD.prototype.update = function () {

	var v1 = new THREE.Vector3();
	var v2 = new THREE.Vector3();

	return function ( camera ) {

		if ( this.objects.length > 1 ) {

			v1.setFromMatrixPosition( camera.matrixWorld );
			v2.setFromMatrixPosition( 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 ( object ) {

	if ( object === undefined ) object = new THREE.LOD();

	THREE.Object3D.prototype.clone.call( this, object );

	for ( var i = 0, l = this.objects.length; i < l; i ++ ) {
		var x = this.objects[ i ].object.clone();
		x.visible = i === 0;
		object.addLevel( x, this.objects[ i ].distance );
	}

	return object;

};

// File:src/objects/Sprite.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Sprite = ( function () {

	var indices = new Uint16Array( [ 0, 1, 2,  0, 2, 3 ] );
	var vertices = new Float32Array( [ - 0.5, - 0.5, 0,   0.5, - 0.5, 0,   0.5, 0.5, 0,   - 0.5, 0.5, 0 ] );
	var uvs = new Float32Array( [ 0, 0,   1, 0,   1, 1,   0, 1 ] );

	var geometry = new THREE.BufferGeometry();
	geometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
	geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
	geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

	return function ( material ) {

		THREE.Object3D.call( this );

		this.type = 'Sprite';

		this.geometry = geometry;
		this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial();

	};

} )();

THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );
THREE.Sprite.prototype.constructor = THREE.Sprite;

THREE.Sprite.prototype.raycast = ( function () {

	var matrixPosition = new THREE.Vector3();

	return function ( raycaster, intersects ) {

		matrixPosition.setFromMatrixPosition( this.matrixWorld );

		var distance = raycaster.ray.distanceToPoint( matrixPosition );

		if ( distance > this.scale.x ) {

			return;

		}

		intersects.push( {

			distance: distance,
			point: this.position,
			face: null,
			object: this

		} );

	};

}() );

THREE.Sprite.prototype.clone = function ( object ) {

	if ( object === undefined ) object = new THREE.Sprite( this.material );

	THREE.Object3D.prototype.clone.call( this, object );

	return object;

};

// Backwards compatibility

THREE.Particle = THREE.Sprite;

// File:src/objects/LensFlare.js

/**
 * @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 );
THREE.LensFlare.prototype.constructor = THREE.LensFlare;


/*
 * 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;

	}

};


// File:src/scenes/Scene.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Scene = function () {

	THREE.Object3D.call( this );

	this.type = 'Scene';

	this.fog = null;
	this.overrideMaterial = null;

	this.autoUpdate = true; // checked by the renderer

};

THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );
THREE.Scene.prototype.constructor = THREE.Scene;

THREE.Scene.prototype.clone = function ( object ) {

	if ( object === undefined ) object = new THREE.Scene();

	THREE.Object3D.prototype.clone.call( this, object );

	if ( this.fog !== null ) object.fog = this.fog.clone();
	if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone();

	object.autoUpdate = this.autoUpdate;
	object.matrixAutoUpdate = this.matrixAutoUpdate;

	return object;

};

// File:src/scenes/Fog.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Fog = function ( color, near, far ) {

	this.name = '';

	this.color = new THREE.Color( color );

	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 );

};

// File:src/scenes/FogExp2.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.FogExp2 = function ( color, density ) {

	this.name = '';

	this.color = new THREE.Color( color );
	this.density = ( density !== undefined ) ? density : 0.00025;

};

THREE.FogExp2.prototype.clone = function () {

	return new THREE.FogExp2( this.color.getHex(), this.density );

};

// File:src/renderers/shaders/ShaderChunk.js

THREE.ShaderChunk = {};

// File:src/renderers/shaders/ShaderChunk/common.glsl

THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2  square( in vec2 a )  { return vec2( a.x*a.x, a.y*a.y ); }\nvec3  square( in vec3 a )  { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4  square( in vec4 a )  { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2  saturate( in vec2 a )  { return clamp( a, 0.0, 1.0 ); }\nvec3  saturate( in vec3 a )  { return clamp( a, 0.0, 1.0 ); }\nvec4  saturate( in vec4 a )  { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a )  { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a )  { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a )  { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2  whiteCompliment( in vec2 a )  { return saturate( vec2(1.0) - a ); }\nvec3  whiteCompliment( in vec3 a )  { return saturate( vec3(1.0) - a ); }\nvec4  whiteCompliment( in vec4 a )  { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n	return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n	return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n	float distance = dot( planeNormal, point-pointOnPlane );\n	return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n	return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n	return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n	if ( decayExponent > 0.0 ) {\n	  return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n	}\n	return 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n	return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n	return a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n	return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n	return a;\n#endif\n}\n";

// File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl

THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n	if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl

THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n	vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n	vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n	float dotProduct = dot( transformedNormal, dirVector );\n	vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n	#ifdef DOUBLE_SIDED\n\n		vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n		#ifdef WRAP_AROUND\n\n			vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n		#endif\n\n	#endif\n\n	#ifdef WRAP_AROUND\n\n		vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n		directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n		#ifdef DOUBLE_SIDED\n\n			directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n		#endif\n\n	#endif\n\n	vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n	#ifdef DOUBLE_SIDED\n\n		vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n	#endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n	for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n		vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n		float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n		lVector = normalize( lVector );\n		float dotProduct = dot( transformedNormal, lVector );\n\n		vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n		#ifdef DOUBLE_SIDED\n\n			vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n			#ifdef WRAP_AROUND\n\n				vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n			#endif\n\n		#endif\n\n		#ifdef WRAP_AROUND\n\n			vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n			pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n			#ifdef DOUBLE_SIDED\n\n				pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n			#endif\n\n		#endif\n\n		vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n		#ifdef DOUBLE_SIDED\n\n			vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n		#endif\n\n	}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n	for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n		vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n		if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n			float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n			lVector = normalize( lVector );\n\n			float dotProduct = dot( transformedNormal, lVector );\n			vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n			#ifdef DOUBLE_SIDED\n\n				vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n				#ifdef WRAP_AROUND\n\n					vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n				#endif\n\n			#endif\n\n			#ifdef WRAP_AROUND\n\n				vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n				spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n				#ifdef DOUBLE_SIDED\n\n					spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n				#endif\n\n			#endif\n\n			vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n			#ifdef DOUBLE_SIDED\n\n				vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n			#endif\n\n		}\n\n	}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n		vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n		float dotProduct = dot( transformedNormal, lVector );\n\n		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n		float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n		vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n		#ifdef DOUBLE_SIDED\n\n			vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n		#endif\n\n	}\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n	vLightBack += ambientLightColor;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl

THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n	uniform vec4 offsetRepeat;\n	uniform sampler2D map;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl

THREE.ShaderChunk[ 'default_vertex'] = "#ifdef USE_SKINNING\n\n	vec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n	vec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n	vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n";

// File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl

THREE.ShaderChunk[ 'map_pars_fragment'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n	varying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n	uniform sampler2D map;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl

THREE.ShaderChunk[ 'skinnormal_vertex'] = "#ifdef USE_SKINNING\n\n	mat4 skinMatrix = mat4( 0.0 );\n	skinMatrix += skinWeight.x * boneMatX;\n	skinMatrix += skinWeight.y * boneMatY;\n	skinMatrix += skinWeight.z * boneMatZ;\n	skinMatrix += skinWeight.w * boneMatW;\n	skinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;\n\n	#ifdef USE_MORPHNORMALS\n\n	vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n	#else\n\n	vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl

THREE.ShaderChunk[ 'logdepthbuf_pars_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n	#ifdef USE_LOGDEPTHBUF_EXT\n\n		varying float vFragDepth;\n\n	#endif\n\n	uniform float logDepthBufFC;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl

THREE.ShaderChunk[ 'lightmap_pars_vertex'] = "#ifdef USE_LIGHTMAP\n\n	varying vec2 vUv2;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl

THREE.ShaderChunk[ 'lights_phong_fragment'] = "#ifndef FLAT_SHADED\n\n	vec3 normal = normalize( vNormal );\n\n	#ifdef DOUBLE_SIDED\n\n		normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n	#endif\n\n#else\n\n	vec3 fdx = dFdx( vViewPosition );\n	vec3 fdy = dFdy( vViewPosition );\n	vec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n	normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n	normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n	for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n		vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n		float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n		lVector = normalize( lVector );\n\n		// diffuse\n\n		float dotProduct = dot( normal, lVector );\n\n		#ifdef WRAP_AROUND\n\n			float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n			float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n			vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n		#else\n\n			float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n		#endif\n\n		totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n				// specular\n\n		vec3 pointHalfVector = normalize( lVector + viewPosition );\n		float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n		float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n		float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n		totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n	}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n	for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n		vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n		float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n		lVector = normalize( lVector );\n\n		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n		if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n			// diffuse\n\n			float dotProduct = dot( normal, lVector );\n\n			#ifdef WRAP_AROUND\n\n				float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n				float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n				vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n			#else\n\n				float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n			#endif\n\n			totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n			// specular\n\n			vec3 spotHalfVector = normalize( lVector + viewPosition );\n			float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n			float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n			float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n			totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n		}\n\n	}\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n		vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n		// diffuse\n\n		float dotProduct = dot( normal, dirVector );\n\n		#ifdef WRAP_AROUND\n\n			float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n			float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n			vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n		#else\n\n			float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n		#endif\n\n		totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n		// specular\n\n		vec3 dirHalfVector = normalize( dirVector + viewPosition );\n		float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n		float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n		/*\n		// fresnel term from skin shader\n		const float F0 = 0.128;\n\n		float base = 1.0 - dot( viewPosition, dirHalfVector );\n		float exponential = pow( base, 5.0 );\n\n		float fresnel = exponential + F0 * ( 1.0 - exponential );\n		*/\n\n		/*\n		// fresnel term from fresnel shader\n		const float mFresnelBias = 0.08;\n		const float mFresnelScale = 0.3;\n		const float mFresnelPower = 5.0;\n\n		float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n		*/\n\n		float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n		// 		dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n		totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n	}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n		vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n		// diffuse\n\n		float dotProduct = dot( normal, lVector );\n		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n		vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n		totalDiffuseLight += hemiColor;\n\n		// specular (sky light)\n\n		vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n		float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n		float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n		// specular (ground light)\n\n		vec3 lVectorGround = -lVector;\n\n		vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n		float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n		float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n		float dotProductGround = dot( normal, lVectorGround );\n\n		float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n		vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n		vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n		totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n	}\n\n#endif\n\n#ifdef METAL\n\n	outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n	outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl

THREE.ShaderChunk[ 'fog_pars_fragment'] = "#ifdef USE_FOG\n\n	uniform vec3 fogColor;\n\n	#ifdef FOG_EXP2\n\n		uniform float fogDensity;\n\n	#else\n\n		uniform float fogNear;\n		uniform float fogFar;\n	#endif\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl

THREE.ShaderChunk[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n	vec3 morphedNormal = vec3( 0.0 );\n\n	morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n	morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n	morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n	morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n	morphedNormal += normal;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl

THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n	uniform float reflectivity;\n	#ifdef ENVMAP_TYPE_CUBE\n		uniform samplerCube envMap;\n	#else\n		uniform sampler2D envMap;\n	#endif\n	uniform float flipEnvMap;\n\n	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n		uniform float refractionRatio;\n\n	#else\n\n		varying vec3 vReflect;\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl

THREE.ShaderChunk[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n	gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl

THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n	uniform sampler2D normalMap;\n	uniform vec2 normalScale;\n\n	// Per-Pixel Tangent Space Normal Mapping\n	// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n	vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n		vec3 q0 = dFdx( eye_pos.xyz );\n		vec3 q1 = dFdy( eye_pos.xyz );\n		vec2 st0 = dFdx( vUv.st );\n		vec2 st1 = dFdy( vUv.st );\n\n		vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n		vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n		vec3 N = normalize( surf_norm );\n\n		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n		mapN.xy = normalScale * mapN.xy;\n		mat3 tsn = mat3( S, T, N );\n		return normalize( tsn * mapN );\n\n	}\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl

THREE.ShaderChunk[ 'lights_phong_pars_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n	varying vec3 vWorldPosition;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl

THREE.ShaderChunk[ 'lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n	varying vec2 vUv2;\n	uniform sampler2D lightMap;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl

THREE.ShaderChunk[ 'shadowmap_vertex'] = "#ifdef USE_SHADOWMAP\n\n	for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n		vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n	}\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl

THREE.ShaderChunk[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n	vWorldPosition = worldPosition.xyz;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/map_fragment.glsl

THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n	vec4 texelColor = texture2D( map, vUv );\n\n	texelColor.xyz = inputToLinear( texelColor.xyz );\n\n	diffuseColor *= texelColor;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl

THREE.ShaderChunk[ 'lightmap_vertex'] = "#ifdef USE_LIGHTMAP\n\n	vUv2 = uv2;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl

THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n	diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl

THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n	varying vec3 vColor;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/color_vertex.glsl

THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n	vColor.xyz = inputToLinear( color.xyz );\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl

THREE.ShaderChunk[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n	#ifdef USE_MORPHTARGETS\n\n	vec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n	#else\n\n	vec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n	#endif\n\n	vec4 skinned = vec4( 0.0 );\n	skinned += boneMatX * skinVertex * skinWeight.x;\n	skinned += boneMatY * skinVertex * skinWeight.y;\n	skinned += boneMatZ * skinVertex * skinWeight.z;\n	skinned += boneMatW * skinVertex * skinWeight.w;\n	skinned  = bindMatrixInverse * skinned;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl

THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n	varying vec3 vReflect;\n\n	uniform float refractionRatio;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl

THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n	outgoingLight = linearToOutput( outgoingLight );\n";

// File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl

THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n	varying vec3 vColor;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl

THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n	uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n	uniform vec3 wrapRGB;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl

THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n	varying vec2 vUv;\n	uniform vec4 offsetRepeat;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl

THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n		// Transforming Normal Vectors with the Inverse Transformation\n		vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n		#ifdef ENVMAP_MODE_REFLECTION\n\n			vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n		#else\n\n			vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n		#endif\n\n	#else\n\n		vec3 reflectVec = vReflect;\n\n	#endif\n\n	#ifdef DOUBLE_SIDED\n		float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n	#else\n		float flipNormal = 1.0;\n	#endif\n\n	#ifdef ENVMAP_TYPE_CUBE\n		vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n	#elif defined( ENVMAP_TYPE_EQUIREC )\n		vec2 sampleUV;\n		sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n		sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n		vec4 envColor = texture2D( envMap, sampleUV );\n\n	#elif defined( ENVMAP_TYPE_SPHERE )\n		vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n		vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n	#endif\n\n	envColor.xyz = inputToLinear( envColor.xyz );\n\n	#ifdef ENVMAP_BLENDING_MULTIPLY\n\n		outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n	#elif defined( ENVMAP_BLENDING_MIX )\n\n		outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n	#elif defined( ENVMAP_BLENDING_ADD )\n\n		outgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl

THREE.ShaderChunk[ 'specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n	uniform sampler2D specularMap;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl

THREE.ShaderChunk[ 'logdepthbuf_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n	gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n	#ifdef USE_LOGDEPTHBUF_EXT\n\n		vFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n		gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n	#endif\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl

THREE.ShaderChunk[ 'morphtarget_pars_vertex'] = "#ifdef USE_MORPHTARGETS\n\n	#ifndef USE_MORPHNORMALS\n\n	uniform float morphTargetInfluences[ 8 ];\n\n	#else\n\n	uniform float morphTargetInfluences[ 4 ];\n\n	#endif\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl

THREE.ShaderChunk[ 'specularmap_fragment'] = "float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n	vec4 texelSpecular = texture2D( specularMap, vUv );\n	specularStrength = texelSpecular.r;\n\n#else\n\n	specularStrength = 1.0;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl

THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n	#ifdef USE_LOGDEPTHBUF_EXT\n\n		float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n	#else\n\n		float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n	#endif\n\n	#ifdef FOG_EXP2\n\n		float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n		fogFactor = whiteCompliment( fogFactor );\n\n	#else\n\n		float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n	#endif\n	\n	outgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl

THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n	uniform sampler2D bumpMap;\n	uniform float bumpScale;\n\n	// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n	// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n	// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n	vec2 dHdxy_fwd() {\n\n		vec2 dSTdx = dFdx( vUv );\n		vec2 dSTdy = dFdy( vUv );\n\n		float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n		float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n		float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n		return vec2( dBx, dBy );\n\n	}\n\n	vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n		vec3 vSigmaX = dFdx( surf_pos );\n		vec3 vSigmaY = dFdy( surf_pos );\n		vec3 vN = surf_norm;		// normalized\n\n		vec3 R1 = cross( vSigmaY, vN );\n		vec3 R2 = cross( vN, vSigmaX );\n\n		float fDet = dot( vSigmaX, R1 );\n\n		vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n		return normalize( abs( fDet ) * surf_norm - vGrad );\n\n	}\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl

THREE.ShaderChunk[ 'defaultnormal_vertex'] = "#ifdef USE_SKINNING\n\n	vec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n	vec3 objectNormal = morphedNormal;\n\n#else\n\n	vec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n	objectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n";

// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl

THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n	uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n	uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n	varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n	uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n	varying vec3 vNormal;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl

THREE.ShaderChunk[ 'skinbase_vertex'] = "#ifdef USE_SKINNING\n\n	mat4 boneMatX = getBoneMatrix( skinIndex.x );\n	mat4 boneMatY = getBoneMatrix( skinIndex.y );\n	mat4 boneMatZ = getBoneMatrix( skinIndex.z );\n	mat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/map_vertex.glsl

THREE.ShaderChunk[ 'map_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n	vUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl

THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n	outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl

THREE.ShaderChunk[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n	varying vec4 vShadowCoord[ MAX_SHADOWS ];\n	uniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/color_fragment.glsl

THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n	diffuseColor.rgb *= vColor;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl

THREE.ShaderChunk[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n	vec3 morphed = vec3( 0.0 );\n	morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n	morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n	morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n	morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n	#ifndef USE_MORPHNORMALS\n\n	morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n	morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n	morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n	morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n	#endif\n\n	morphed += position;\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl

THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n	vec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n	vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n	#ifdef ENVMAP_MODE_REFLECTION\n\n		vReflect = reflect( cameraToVertex, worldNormal );\n\n	#else\n\n		vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl

THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n	#ifdef SHADOWMAP_DEBUG\n\n		vec3 frustumColors[3];\n		frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n		frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n		frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n	#endif\n\n	#ifdef SHADOWMAP_CASCADE\n\n		int inFrustumCount = 0;\n\n	#endif\n\n	float fDepth;\n	vec3 shadowColor = vec3( 1.0 );\n\n	for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n		vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n				// if ( something && something ) breaks ATI OpenGL shader compiler\n				// if ( all( something, something ) ) using this instead\n\n		bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n		bool inFrustum = all( inFrustumVec );\n\n				// don't shadow pixels outside of light frustum\n				// use just first frustum (for cascades)\n				// don't shadow pixels behind far plane of light frustum\n\n		#ifdef SHADOWMAP_CASCADE\n\n			inFrustumCount += int( inFrustum );\n			bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n		#else\n\n			bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n		#endif\n\n		bool frustumTest = all( frustumTestVec );\n\n		if ( frustumTest ) {\n\n			shadowCoord.z += shadowBias[ i ];\n\n			#if defined( SHADOWMAP_TYPE_PCF )\n\n						// Percentage-close filtering\n						// (9 pixel kernel)\n						// http://fabiensanglard.net/shadowmappingPCF/\n\n				float shadow = 0.0;\n\n		/*\n						// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n						// must enroll loop manually\n\n				for ( float y = -1.25; y <= 1.25; y += 1.25 )\n					for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n						vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n								// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n								//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n						float fDepth = unpackDepth( rgbaDepth );\n\n						if ( fDepth < shadowCoord.z )\n							shadow += 1.0;\n\n				}\n\n				shadow /= 9.0;\n\n		*/\n\n				const float shadowDelta = 1.0 / 9.0;\n\n				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n				float dx0 = -1.25 * xPixelOffset;\n				float dy0 = -1.25 * yPixelOffset;\n				float dx1 = 1.25 * xPixelOffset;\n				float dy1 = 1.25 * yPixelOffset;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n			#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n						// Percentage-close filtering\n						// (9 pixel kernel)\n						// http://fabiensanglard.net/shadowmappingPCF/\n\n				float shadow = 0.0;\n\n				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n				float dx0 = -1.0 * xPixelOffset;\n				float dy0 = -1.0 * yPixelOffset;\n				float dx1 = 1.0 * xPixelOffset;\n				float dy1 = 1.0 * yPixelOffset;\n\n				mat3 shadowKernel;\n				mat3 depthKernel;\n\n				depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n				depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n				depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n				depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n				depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n				depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n				depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n				depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n				depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n				vec3 shadowZ = vec3( shadowCoord.z );\n				shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n				shadowKernel[0] *= vec3(0.25);\n\n				shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n				shadowKernel[1] *= vec3(0.25);\n\n				shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n				shadowKernel[2] *= vec3(0.25);\n\n				vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n				shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n				shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n				vec4 shadowValues;\n				shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n				shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n				shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n				shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n				shadow = dot( shadowValues, vec4( 1.0 ) );\n\n				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n			#else\n\n				vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n				float fDepth = unpackDepth( rgbaDepth );\n\n				if ( fDepth < shadowCoord.z )\n\n		// spot with multiple shadows is darker\n\n					shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n		// spot with multiple shadows has the same color as single shadow spot\n\n		// 					shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n			#endif\n\n		}\n\n\n		#ifdef SHADOWMAP_DEBUG\n\n			#ifdef SHADOWMAP_CASCADE\n\n				if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n			#else\n\n				if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n			#endif\n\n		#endif\n\n	}\n\n	// NOTE: I am unsure if this is correct in linear space.  -bhouston, Dec 29, 2014\n	shadowColor = inputToLinear( shadowColor );\n\n	outgoingLight = outgoingLight * shadowColor;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl

THREE.ShaderChunk[ 'worldpos_vertex'] = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n	#ifdef USE_SKINNING\n\n		vec4 worldPosition = modelMatrix * skinned;\n\n	#elif defined( USE_MORPHTARGETS )\n\n		vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n	#else\n\n		vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl

THREE.ShaderChunk[ 'shadowmap_pars_fragment'] = "#ifdef USE_SHADOWMAP\n\n	uniform sampler2D shadowMap[ MAX_SHADOWS ];\n	uniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n	uniform float shadowDarkness[ MAX_SHADOWS ];\n	uniform float shadowBias[ MAX_SHADOWS ];\n\n	varying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n	float unpackDepth( const in vec4 rgba_depth ) {\n\n		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 );\n		float depth = dot( rgba_depth, bit_shift );\n		return depth;\n\n	}\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl

THREE.ShaderChunk[ 'skinning_pars_vertex'] = "#ifdef USE_SKINNING\n\n	uniform mat4 bindMatrix;\n	uniform mat4 bindMatrixInverse;\n\n	#ifdef BONE_TEXTURE\n\n		uniform sampler2D boneTexture;\n		uniform int boneTextureWidth;\n		uniform int boneTextureHeight;\n\n		mat4 getBoneMatrix( const in float i ) {\n\n			float j = i * 4.0;\n			float x = mod( j, float( boneTextureWidth ) );\n			float y = floor( j / float( boneTextureWidth ) );\n\n			float dx = 1.0 / float( boneTextureWidth );\n			float dy = 1.0 / float( boneTextureHeight );\n\n			y = dy * ( y + 0.5 );\n\n			vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n			vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n			vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n			vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n			mat4 bone = mat4( v1, v2, v3, v4 );\n\n			return bone;\n\n		}\n\n	#else\n\n		uniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n		mat4 getBoneMatrix( const in float i ) {\n\n			mat4 bone = boneGlobalMatrices[ int(i) ];\n			return bone;\n\n		}\n\n	#endif\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl

THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n	uniform float logDepthBufFC;\n\n	#ifdef USE_LOGDEPTHBUF_EXT\n\n		#extension GL_EXT_frag_depth : enable\n		varying float vFragDepth;\n\n	#endif\n\n#endif";

// File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl

THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n	diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n";

// File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl

THREE.ShaderChunk[ 'alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n	uniform sampler2D alphaMap;\n\n#endif\n";

// File:src/renderers/shaders/UniformsUtils.js

/**
 * Uniform Utilities
 */

THREE.UniformsUtils = {

	merge: function ( uniforms ) {

		var merged = {};

		for ( var u = 0; u < uniforms.length; u ++ ) {

			var tmp = this.clone( uniforms[ u ] );

			for ( var p in tmp ) {

				merged[ p ] = tmp[ p ];

			}

		}

		return merged;

	},

	clone: function ( uniforms_src ) {

		var uniforms_dst = {};

		for ( var u in uniforms_src ) {

			uniforms_dst[ u ] = {};

			for ( var p in uniforms_src[ u ] ) {

				var 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;

	}

};

// File:src/renderers/shaders/UniformsLib.js

/**
 * Uniforms library for shared webgl shaders
 */

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 },
		"alphaMap" : { type: "t", value: null },

		"envMap" : { type: "t", value: null },
		"flipEnvMap" : { type: "f", value: - 1 },
		"reflectivity" : { type: "f", value: 1.0 },
		"refractionRatio" : { type: "f", value: 0.98 },

		"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: [] },
		"pointLightDecay" : { 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: [] },
		"spotLightDecay" : { 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 },
		"offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },

		"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: [] }

	}

};

// File:src/renderers/shaders/ShaderLib.js

/**
 * Webgl Shader Library for three.js
 *
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 */


THREE.ShaderLib = {

	'basic': {

		uniforms: THREE.UniformsUtils.merge( [

			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "shadowmap" ]

		] ),

		vertexShader: [

			THREE.ShaderChunk[ "common" ],
			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" ],
			THREE.ShaderChunk[ "logdepthbuf_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[ "logdepthbuf_vertex" ],

				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform vec3 diffuse;",
			"uniform float opacity;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "alphamap_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" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
			"	vec4 diffuseColor = vec4( diffuse, opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "alphamap_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "specularmap_fragment" ],

			"	outgoingLight = diffuseColor.rgb;", // simple shader

				THREE.ShaderChunk[ "lightmap_fragment" ],		// TODO: Light map on an otherwise unlit surface doesn't make sense.
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],		// TODO: Shadows on an otherwise unlit surface doesn't make sense.

				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

				THREE.ShaderChunk[ "fog_fragment" ],

			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].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( 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[ "common" ],
			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" ],
			THREE.ShaderChunk[ "logdepthbuf_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[ "logdepthbuf_vertex" ],

				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "lights_lambert_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform vec3 diffuse;",
			"uniform vec3 emissive;",
			"uniform float opacity;",

			"varying vec3 vLightFront;",

			"#ifdef DOUBLE_SIDED",

			"	varying vec3 vLightBack;",

			"#endif",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "alphamap_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" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
			"	vec4 diffuseColor = vec4( diffuse, opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "alphamap_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 )",
			"			outgoingLight += diffuseColor.rgb * vLightFront + emissive;",
			"		else",
			"			outgoingLight += diffuseColor.rgb * vLightBack + emissive;",

			"	#else",

			"		outgoingLight += diffuseColor.rgb * vLightFront + emissive;",

			"	#endif",

				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],

				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

				THREE.ShaderChunk[ "fog_fragment" ],

			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].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" ],

			{
				"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;",

			"#ifndef FLAT_SHADED",

			"	varying vec3 vNormal;",

			"#endif",

			THREE.ShaderChunk[ "common" ],
			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" ],
			THREE.ShaderChunk[ "logdepthbuf_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" ],

			"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED

			"	vNormal = normalize( transformedNormal );",

			"#endif",

				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"	vViewPosition = -mvPosition.xyz;",

				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "lights_phong_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"#define PHONG",

			"uniform vec3 diffuse;",
			"uniform vec3 emissive;",
			"uniform vec3 specular;",
			"uniform float shininess;",
			"uniform float opacity;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "alphamap_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" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
			"	vec4 diffuseColor = vec4( diffuse, opacity );",

				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[ "lights_phong_fragment" ],

				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],

				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

				THREE.ShaderChunk[ "fog_fragment" ],

			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].join("\n")

	},

	'particle_basic': {

		uniforms: THREE.UniformsUtils.merge( [

			THREE.UniformsLib[ "particle" ],
			THREE.UniformsLib[ "shadowmap" ]

		] ),

		vertexShader: [

			"uniform float size;",
			"uniform float scale;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			THREE.ShaderChunk[ "logdepthbuf_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[ "logdepthbuf_vertex" ],
				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform vec3 psColor;",
			"uniform float opacity;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_particle_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
			"	vec4 diffuseColor = vec4( psColor, opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
				THREE.ShaderChunk[ "map_particle_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],

			"	outgoingLight = diffuseColor.rgb;", // simple shader

				THREE.ShaderChunk[ "shadowmap_fragment" ],
				THREE.ShaderChunk[ "fog_fragment" ],

			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].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[ "common" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],

			"void main() {",

				THREE.ShaderChunk[ "color_vertex" ],

			"	vLineDistance = scale * lineDistance;",

			"	vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
			"	gl_Position = projectionMatrix * mvPosition;",

				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform vec3 diffuse;",
			"uniform float opacity;",

			"uniform float dashSize;",
			"uniform float totalSize;",

			"varying float vLineDistance;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	if ( mod( vLineDistance, totalSize ) > dashSize ) {",

			"		discard;",

			"	}",

			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
			"	vec4 diffuseColor = vec4( diffuse, opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],

			"	outgoingLight = diffuseColor.rgb;", // simple shader

				THREE.ShaderChunk[ "fog_fragment" ],

			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].join("\n")

	},

	'depth': {

		uniforms: {

			"mNear": { type: "f", value: 1.0 },
			"mFar" : { type: "f", value: 2000.0 },
			"opacity" : { type: "f", value: 1.0 }

		},

		vertexShader: [

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],

			"void main() {",

				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform float mNear;",
			"uniform float mFar;",
			"uniform float opacity;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],

			"	#ifdef USE_LOGDEPTHBUF_EXT",

			"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",

			"	#else",

			"		float depth = gl_FragCoord.z / gl_FragCoord.w;",

			"	#endif",

			"	float color = 1.0 - smoothstep( mNear, mFar, depth );",
			"	gl_FragColor = vec4( vec3( color ), opacity );",   // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects

			"}"

		].join("\n")

	},

	'normal': {

		uniforms: {

			"opacity" : { type: "f", value: 1.0 }

		},

		vertexShader: [

			"varying vec3 vNormal;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],

			"void main() {",

			"	vNormal = normalize( normalMatrix * normal );",

				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform float opacity;",
			"varying vec3 vNormal;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],

			"}"

		].join("\n")

	},

	/* -------------------------------------------------------------------------
	//	Cube map shader
	 ------------------------------------------------------------------------- */

	'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() {",

			"	vWorldPosition = transformDirection( position, modelMatrix );",

			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform samplerCube tCube;",
			"uniform float tFlip;",

			"varying vec3 vWorldPosition;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],

			"}"

		].join("\n")

	},

	/* -------------------------------------------------------------------------
	//	Cube map shader
	 ------------------------------------------------------------------------- */

	'equirect': {

		uniforms: { "tEquirect": { type: "t", value: null },
					"tFlip": { type: "f", value: - 1 } },

		vertexShader: [

			"varying vec3 vWorldPosition;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],

			"void main() {",

			"	vWorldPosition = transformDirection( position, modelMatrix );",

			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform sampler2D tEquirect;",
			"uniform float tFlip;",

			"varying vec3 vWorldPosition;",

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

				// "	gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",
				"vec3 direction = normalize( vWorldPosition );",
				"vec2 sampleUV;",
				"sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );",
				"sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;",
				"gl_FragColor = texture2D( tEquirect, sampleUV );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],

			"}"

		].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
	 * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/
	 */

	'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[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			"}"

		].join("\n"),

		fragmentShader: [

			THREE.ShaderChunk[ "common" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"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 = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // "	vec4 res = fract( depth * bit_shift );",
			"	res -= res.xxyz * bit_mask;",
			"	return res;",

			"}",

			"void main() {",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],

			"	#ifdef USE_LOGDEPTHBUF_EXT",

			"		gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );",

			"	#else",

			"		gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );",

			"	#endif",

				//"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")

	}

};

// File:src/renderers/WebGLRenderer.js

/**
 * @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' ),
	_context = parameters.context !== undefined ? parameters.context : null,

	pixelRatio = 1,

	_precision = parameters.precision !== undefined ? parameters.precision : 'highp',

	_alpha = parameters.alpha !== undefined ? parameters.alpha : false,
	_depth = parameters.depth !== undefined ? parameters.depth : true,
	_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
	_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
	_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
	_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
	_logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false,

	_clearColor = new THREE.Color( 0x000000 ),
	_clearAlpha = 0;

	var lights = [];

	var _webglObjects = {};
	var _webglObjectsImmediate = [];

	var opaqueObjects = [];
	var transparentObjects = [];

	var sprites = [];
	var lensFlares = [];

	// public properties

	this.domElement = _canvas;
	this.context = null;

	// clearing

	this.autoClear = true;
	this.autoClearColor = true;
	this.autoClearDepth = true;
	this.autoClearStencil = true;

	// scene graph

	this.sortObjects = true;

	// physically based shading

	this.gammaFactor = 2.0;	// for backwards compatibility
	this.gammaInput = false;
	this.gammaOutput = false;

	// shadow map

	this.shadowMapEnabled = false;
	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;

	// 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 = [],

	// internal state cache

	_currentProgram = null,
	_currentFramebuffer = null,
	_currentMaterialId = - 1,
	_currentGeometryProgram = '',
	_currentCamera = null,

	_usedTextureUnits = 0,

	_viewportX = 0,
	_viewportY = 0,
	_viewportWidth = _canvas.width,
	_viewportHeight = _canvas.height,
	_currentWidth = 0,
	_currentHeight = 0,

	// frustum

	_frustum = new THREE.Frustum(),

	 // camera matrices cache

	_projScreenMatrix = 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:[], positions: [] },
		point: { length: 0, colors: [], positions: [], distances: [], decays: [] },
		spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] },
		hemi: { length: 0, skyColors: [], groundColors: [], positions: [] }

	};

	// initialize

	var _gl;

	var ctxLost = function ( event ) {

	    event.preventDefault();

	    resetGLState();
	    setDefaultGLState();

	    _webglObjects = {};

	};

	try {

		var attributes = {
			alpha: _alpha,
			depth: _depth,
			stencil: _stencil,
			antialias: _antialias,
			premultipliedAlpha: _premultipliedAlpha,
			preserveDrawingBuffer: _preserveDrawingBuffer
		};

		_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );

		if ( _gl === null ) {

			if ( _canvas.getContext( 'webgl') !== null ) {

				throw 'Error creating WebGL context with your selected attributes.';

			} else {

				throw 'Error creating WebGL context.';

			}

		}

		_canvas.addEventListener( 'webglcontextlost', ctxLost, false);

	} catch ( error ) {

		THREE.error( 'THREE.WebGLRenderer: ' + error );

	}

	this.dispose = function () {
	    _canvas.removeEventListener('webglcontextlost', ctxLost, false);
	}

	var state = new THREE.WebGLState( _gl, paramThreeToGL );

	if ( _gl.getShaderPrecisionFormat === undefined ) {

		_gl.getShaderPrecisionFormat = function () {

			return {
				'rangeMin': 1,
				'rangeMax': 1,
				'precision': 1
			};

		}

	}

	var extensions = new THREE.WebGLExtensions( _gl );

	extensions.get( 'OES_texture_float' );
	extensions.get( 'OES_texture_float_linear' );
	extensions.get( 'OES_texture_half_float' );
	extensions.get( 'OES_texture_half_float_linear' );
	extensions.get( 'OES_standard_derivatives' );

	if ( _logarithmicDepthBuffer ) {

		extensions.get( 'EXT_frag_depth' );

	}

	//

	var glClearColor = function ( r, g, b, a ) {

		if ( _premultipliedAlpha === true ) {

			r *= a; g *= a; b *= a;

		}

		_gl.clearColor( r, g, b, a );

	};

	var setDefaultGLState = function () {

		_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.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );

		glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );

	};

	var resetGLState = function () {

		_currentProgram = null;
		_currentCamera = null;

		_currentGeometryProgram = '';
		_currentMaterialId = - 1;

		_lightsNeedUpdate = true;

		state.reset();

	};

	setDefaultGLState();

	this.context = _gl;
	this.state = state;

	// 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 _supportsVertexTextures = _maxVertexTextures > 0;
	var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' );

	//

	var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
	var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );

	var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
	var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );

	var getCompressedTextureFormats = ( function () {

		var array;

		return function () {

			if ( array !== undefined ) {

				return array;

			}

			array = [];

			if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) {

				var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS );

				for ( var i = 0; i < formats.length; i ++ ) {

					array.push( formats[ i ] );

				}

			}

			return array;

		};

	} )();

	// 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';
			THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' );

		} else {

			_precision = 'lowp';
			THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' );

		}

	}

	if ( _precision === 'mediump' && ! mediumpAvailable ) {

		_precision = 'lowp';
		THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' );

	}

	// Plugins

	var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate );

	var spritePlugin = new THREE.SpritePlugin( this, sprites );
	var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares );

	// API

	this.getContext = function () {

		return _gl;

	};

	this.forceContextLoss = function () {

		extensions.get( 'WEBGL_lose_context' ).loseContext();

	};

	this.supportsVertexTextures = function () {

		return _supportsVertexTextures;

	};

	this.supportsFloatTextures = function () {

		return extensions.get( 'OES_texture_float' );

	};

	this.supportsHalfFloatTextures = function () {

		return extensions.get( 'OES_texture_half_float' );

	};

	this.supportsStandardDerivatives = function () {

		return extensions.get( 'OES_standard_derivatives' );

	};

	this.supportsCompressedTextureS3TC = function () {

		return extensions.get( 'WEBGL_compressed_texture_s3tc' );

	};

	this.supportsCompressedTexturePVRTC = function () {

		return extensions.get( 'WEBGL_compressed_texture_pvrtc' );

	};

	this.supportsBlendMinMax = function () {

		return extensions.get( 'EXT_blend_minmax' );

	};

	this.getMaxAnisotropy = ( function () {

		var value;

		return function () {

			if ( value !== undefined ) {

				return value;

			}

			var extension = extensions.get( 'EXT_texture_filter_anisotropic' );

			value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;

			return value;

		}

	} )();

	this.getPrecision = function () {

		return _precision;

	};

	this.getPixelRatio = function () {

		return pixelRatio;

	};

	this.setPixelRatio = function ( value ) {

		pixelRatio = value;

	};

	this.setSize = function ( width, height, updateStyle ) {

		_canvas.width = width * pixelRatio;
		_canvas.height = height * pixelRatio;

		if ( updateStyle !== false ) {

			_canvas.style.width = width + 'px';
			_canvas.style.height = height + 'px';

		}

		this.setViewport( 0, 0, width, height );

	};

	this.setViewport = function ( x, y, width, height ) {

		_viewportX = x * pixelRatio;
		_viewportY = y * pixelRatio;

		_viewportWidth = width * pixelRatio;
		_viewportHeight = height * pixelRatio;

		_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );

	};

	this.setScissor = function ( x, y, width, height ) {

		_gl.scissor(
			x * pixelRatio,
			y * pixelRatio,
			width * pixelRatio,
			height * pixelRatio
		);

	};

	this.enableScissorTest = function ( enable ) {

		enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );

	};

	// Clearing

	this.getClearColor = function () {

		return _clearColor;

	};

	this.setClearColor = function ( color, alpha ) {

		_clearColor.set( color );

		_clearAlpha = alpha !== undefined ? alpha : 1;

		glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );

	};

	this.getClearAlpha = function () {

		return _clearAlpha;

	};

	this.setClearAlpha = function ( alpha ) {

		_clearAlpha = alpha;

		glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _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.clearColor = function () {

		_gl.clear( _gl.COLOR_BUFFER_BIT );

	};

	this.clearDepth = function () {

		_gl.clear( _gl.DEPTH_BUFFER_BIT );

	};

	this.clearStencil = function () {

		_gl.clear( _gl.STENCIL_BUFFER_BIT );

	};

	this.clearTarget = function ( renderTarget, color, depth, stencil ) {

		this.setRenderTarget( renderTarget );
		this.clear( color, depth, stencil );

	};

	// Reset

	this.resetGLState = resetGLState;

	// 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 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 numMorphTargets = geometryGroup.numMorphTargets;

		if ( numMorphTargets ) {

			geometryGroup.__webglMorphTargetsBuffers = [];

			for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) {

				geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );

			}

		}

		var numMorphNormals = geometryGroup.numMorphNormals;

		if ( numMorphNormals ) {

			geometryGroup.__webglMorphNormalsBuffers = [];

			for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) {

				geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );

			}

		}

		_this.info.memory.geometries ++;

	};

	// Events

	var onObjectRemoved = function ( event ) {

		var object = event.target;

		object.traverse( function ( child ) {

			child.removeEventListener( 'remove', onObjectRemoved );

			removeObject( child );

		} );

	};

	var onGeometryDispose = function ( event ) {

		var geometry = event.target;

		geometry.removeEventListener( 'dispose', onGeometryDispose );

		deallocateGeometry( geometry );

	};

	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 deleteBuffers = function ( geometry ) {

		var buffers = [
			'__webglVertexBuffer',
			'__webglNormalBuffer',
			'__webglTangentBuffer',
			'__webglColorBuffer',
			'__webglUVBuffer',
			'__webglUV2Buffer',

			'__webglSkinIndicesBuffer',
			'__webglSkinWeightsBuffer',

			'__webglFaceBuffer',
			'__webglLineBuffer',

			'__webglLineDistanceBuffer'
		];

		for ( var i = 0, l = buffers.length; i < l; i ++ ) {

			var name = buffers[ i ];

			if ( geometry[ name ] !== undefined ) {

				_gl.deleteBuffer( geometry[ name ] );

				delete geometry[ name ];

			}

		}

		// custom attributes

		if ( geometry.__webglCustomAttributesList !== undefined ) {

			for ( var name in geometry.__webglCustomAttributesList ) {

				_gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer );

			}

			delete geometry.__webglCustomAttributesList;

		}

		_this.info.memory.geometries --;

	};

	var deallocateGeometry = function ( geometry ) {

		delete geometry.__webglInit;

		if ( geometry instanceof THREE.BufferGeometry ) {

			for ( var name in geometry.attributes ) {

				var attribute = geometry.attributes[ name ];

				if ( attribute.buffer !== undefined ) {

					_gl.deleteBuffer( attribute.buffer );

					delete attribute.buffer;

				}

			}

			_this.info.memory.geometries --;

		} else {

			var geometryGroupsList = geometryGroups[ geometry.id ];

			if ( geometryGroupsList !== undefined ) {

				for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) {

					var geometryGroup = geometryGroupsList[ i ];

					if ( geometryGroup.numMorphTargets !== undefined ) {

						for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {

							_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );

						}

						delete geometryGroup.__webglMorphTargetsBuffers;

					}

					if ( geometryGroup.numMorphNormals !== undefined ) {

						for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {

							_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );

						}

						delete geometryGroup.__webglMorphNormalsBuffers;

					}

					deleteBuffers( geometryGroup );

				}

				delete geometryGroups[ geometry.id ];

			} else {

				deleteBuffers( geometry );

			}

		}

		// TOFIX: Workaround for deleted geometry being currently bound

		_currentGeometryProgram = '';

	};

	var deallocateTexture = function ( texture ) {

		if ( texture.image && texture.image.__webglTextureCube ) {

			// cube texture

			_gl.deleteTexture( texture.image.__webglTextureCube );

			delete texture.image.__webglTextureCube;

		} else {

			// 2D texture

			if ( texture.__webglInit === undefined ) return;

			_gl.deleteTexture( texture.__webglTexture );

			delete texture.__webglTexture;
			delete texture.__webglInit;

		}

	};

	var deallocateRenderTarget = function ( renderTarget ) {

		if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return;

		_gl.deleteTexture( renderTarget.__webglTexture );

		delete 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 );

		}

		delete renderTarget.__webglFramebuffer;
		delete renderTarget.__webglRenderbuffer;

	};

	var deallocateMaterial = function ( material ) {

		var program = material.program.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 --;

		}

	};

	// Buffer initialization

	function initCustomAttributes ( object ) {

		var geometry = object.geometry;
		var material = object.material;

		var nvertices = geometry.vertices.length;

		if ( material.attributes ) {

			if ( geometry.__webglCustomAttributesList === undefined ) {

				geometry.__webglCustomAttributesList = [];

			}

			for ( var name in material.attributes ) {

				var attribute = material.attributes[ name ];

				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 = name;

					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.__webglParticleCount = nvertices;

		initCustomAttributes( 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( object );

	};

	function initMeshBuffers ( geometryGroup, object ) {

		var geometry = object.geometry,
			faces3 = geometryGroup.faces3,

			nvertices = faces3.length * 3,
			ntris     = faces3.length * 1,
			nlines    = faces3.length * 3,

			material = getBufferMaterial( object, geometryGroup );

		geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
		geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
		geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
		geometryGroup.__uvArray = new Float32Array( nvertices * 2 );

		if ( geometry.faceVertexUvs.length > 1 ) {

			geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );

		}

		if ( geometry.hasTangents ) {

			geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );

		}

		if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {

			geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
			geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );

		}

		var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3

		geometryGroup.__typeArray = UintArray;
		geometryGroup.__faceArray = new UintArray( ntris * 3 );
		geometryGroup.__lineArray = new UintArray( nlines * 2 );

		var numMorphTargets = geometryGroup.numMorphTargets;

		if ( numMorphTargets ) {

			geometryGroup.__morphTargetsArrays = [];

			for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) {

				geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );

			}

		}

		var numMorphNormals = geometryGroup.numMorphNormals;

		if ( numMorphNormals ) {

			geometryGroup.__morphNormalsArrays = [];

			for ( var m = 0, ml = 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 name 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[ name ];

				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 = name;

					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 materialNeedsFaceNormals ( material ) {

		return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading;

	}

	// Buffer setting

	function setParticleBuffers ( geometry, hint, object ) {

		var v, c, vertex, offset, color,

		vertices = geometry.vertices,
		vl = vertices.length,

		colors = geometry.colors,
		cl = colors.length,

		vertexArray = geometry.__vertexArray,
		colorArray = geometry.__colorArray,

		dirtyVertices = geometry.verticesNeedUpdate,
		dirtyColors = geometry.colorsNeedUpdate,

		customAttributes = geometry.__webglCustomAttributesList,
		i, il,
		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 ( 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;

						}

					}

				}

				_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );

				customAttribute.needsUpdate = false;

			}

		}

	}

	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,
		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 );

					customAttribute.needsUpdate = false;

				}

			}

		}

	}

	function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {

		if ( ! geometryGroup.__inittedArrays ) {

			return;

		}

		var needsFaceNormals = materialNeedsFaceNormals( material );

		var f, fl, fi, face,
		vertexNormals, faceNormal,
		vertexColors, faceColor,
		vertexTangents,
		uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3,
		c1, c2, c3,
		sw1, sw2, sw3,
		si1, si2, si3,
		i, il,
		vn, uvi, uv2i,
		vk, vkl, vka,
		nka, chf, faceVertexNormals,

		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,

		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,
		obj_faces = geometry.faces,

		obj_uvs  = geometry.faceVertexUvs[ 0 ],
		obj_uvs2 = geometry.faceVertexUvs[ 1 ],

		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;

			}

			_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 ( needsFaceNormals ) {

							n1 = morphNormals[ vk ].faceNormals[ chf ];
							n2 = n1;
							n3 = n1;

						} else {

							faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];

							n1 = faceVertexNormals.a;
							n2 = faceVertexNormals.b;
							n3 = faceVertexNormals.c;

						}

						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;

				}

				_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;

			}

			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 ) {

			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 && material.vertexColors === 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;

			}

			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;

			}

			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );

		}

		if ( dirtyNormals ) {

			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 && needsFaceNormals === false ) {

					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;

					}

				}

			}

			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
			_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );

		}

		if ( dirtyUvs && obj_uvs ) {

			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;

				}

			}

			if ( offset_uv > 0 ) {

				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
				_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );

			}

		}

		if ( dirtyUvs && obj_uvs2 ) {

			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;

				}

			}

			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;

			}

			_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;

				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;

						}

					} 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;

						}

					}

				} 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;

						}

					} 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;

						}

					}

				} 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;

						}

					} 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;

						}

					} 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;

						}

					}

				} 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;

						}

					} 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;

						}

					} 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;

						}

					}

				}

				_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;

		}

	};

	// Buffer rendering

	this.renderBufferImmediate = function ( object, program, material ) {

		state.initAttributes();

		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 );

			state.enableAttribute( 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 instanceof THREE.MeshPhongMaterial === false &&
				   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 );

			state.enableAttribute( 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 );

			state.enableAttribute( 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 );

			state.enableAttribute( program.attributes.color );

			_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );

		}

		state.disableUnusedAttributes();

		_gl.drawArrays( _gl.TRIANGLES, 0, object.count );

		object.count = 0;

	};

	function setupVertexAttributes( material, program, geometry, startIndex ) {

		var geometryAttributes = geometry.attributes;

		var programAttributes = program.attributes;
		var programAttributesKeys = program.attributesKeys;

		for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) {

			var key = programAttributesKeys[ i ];
			var programAttribute = programAttributes[ key ];

			if ( programAttribute >= 0 ) {

				var geometryAttribute = geometryAttributes[ key ];

				if ( geometryAttribute !== undefined ) {

					var size = geometryAttribute.itemSize;

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );

					state.enableAttribute( programAttribute );

					_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32

				} else if ( material.defaultAttributeValues !== undefined ) {

					if ( material.defaultAttributeValues[ key ].length === 2 ) {

						_gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] );

					} else if ( material.defaultAttributeValues[ key ].length === 3 ) {

						_gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] );

					}

				}

			}

		}

		state.disableUnusedAttributes();

	}

	this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {

		if ( material.visible === false ) return;

		updateObject( object );

		var program = setProgram( camera, lights, fog, material, object );

		var updateBuffers = false,
			wireframeBit = material.wireframe ? 1 : 0,
			geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit;

		if ( geometryProgram !== _currentGeometryProgram ) {

			_currentGeometryProgram = geometryProgram;
			updateBuffers = true;

		}

		if ( updateBuffers ) {

			state.initAttributes();

		}

		// render mesh

		if ( object instanceof THREE.Mesh ) {

			var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES;

			var index = geometry.attributes.index;

			if ( index ) {

				// indexed triangles

				var type, size;

				if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {

					type = _gl.UNSIGNED_INT;
					size = 4;

				} else {

					type = _gl.UNSIGNED_SHORT;
					size = 2;

				}

				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					if ( updateBuffers ) {

						setupVertexAttributes( material, program, geometry, 0 );
						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

					}
				//console.log(mode === _gl.LINES ? 'nowires' : 'wires');
					_gl.drawElements( mode, index.array.length, type, 0 );

					_this.info.render.calls ++;
					_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
					_this.info.render.faces += index.array.length / 3;

				} else {

					// 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

					updateBuffers = true;

					for ( var i = 0, il = offsets.length; i < il; i ++ ) {

						var startIndex = offsets[ i ].index;

						if ( updateBuffers ) {

							setupVertexAttributes( material, program, geometry, startIndex );
							_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

						}

						// render indexed triangles

						_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );

						_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;

					}

				}

			} else {

				// non-indexed triangles

				if ( updateBuffers ) {

					setupVertexAttributes( material, program, geometry, 0 );

				}

				var position = geometry.attributes[ 'position' ];

				// render non-indexed triangles

				_gl.drawArrays( mode, 0, position.array.length / position.itemSize );

				_this.info.render.calls ++;
				_this.info.render.vertices += position.array.length / position.itemSize;
				_this.info.render.faces += position.array.length / ( 3 * position.itemSize );

			}

		} else if ( object instanceof THREE.PointCloud ) {

			// render particles

			var mode = _gl.POINTS;

			var index = geometry.attributes.index;

			if ( index ) {

				// indexed points

				var type, size;

				if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {

					type = _gl.UNSIGNED_INT;
					size = 4;

				} else {

					type = _gl.UNSIGNED_SHORT;
					size = 2;

				}

				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					if ( updateBuffers ) {

						setupVertexAttributes( material, program, geometry, 0 );
						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

					}

					_gl.drawElements( mode, index.array.length, type, 0);

					_this.info.render.calls ++;
					_this.info.render.points += index.array.length;

				} else {

					// 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 ) {

							setupVertexAttributes( material, program, geometry, startIndex );
							_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

						}

						// render indexed points

						_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );

						_this.info.render.calls ++;
						_this.info.render.points += offsets[ i ].count;

					}

				}

			} else {

				// non-indexed points

				if ( updateBuffers ) {

					setupVertexAttributes( material, program, geometry, 0 );

				}

				var position = geometry.attributes.position;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					_gl.drawArrays( mode, 0, position.array.length / 3 );

					_this.info.render.calls ++;
					_this.info.render.points += position.array.length / 3;

				} else {

					for ( var i = 0, il = offsets.length; i < il; i ++ ) {

						_gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );

						_this.info.render.calls ++;
						_this.info.render.points += offsets[ i ].count;

					}

				}

			}

		} else if ( object instanceof THREE.Line ) {

			var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;

			state.setLineWidth( material.linewidth * pixelRatio );

			var index = geometry.attributes.index;

			if ( index ) {

				// indexed lines

				var type, size;

				if ( index.array instanceof Uint32Array ) {

					type = _gl.UNSIGNED_INT;
					size = 4;

				} else {

					type = _gl.UNSIGNED_SHORT;
					size = 2;

				}

				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					if ( updateBuffers ) {

						setupVertexAttributes( material, program, geometry, 0 );
						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

					}

					_gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array

					_this.info.render.calls ++;
					_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared

				} else {

					// 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 ) {

							setupVertexAttributes( material, program, geometry, startIndex );
							_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

						}

						// render indexed lines

						_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array

						_this.info.render.calls ++;
						_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared

					}

				}

			} else {

				// non-indexed lines

				if ( updateBuffers ) {

					setupVertexAttributes( material, program, geometry, 0 );

				}

				var position = geometry.attributes.position;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					_gl.drawArrays( mode, 0, position.array.length / 3 );

					_this.info.render.calls ++;
					_this.info.render.vertices += position.array.length / 3;

				} else {

					for ( var i = 0, il = offsets.length; i < il; i ++ ) {

						_gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );

						_this.info.render.calls ++;
						_this.info.render.vertices += offsets[ i ].count;

					}

				}

			}

		}

	};

	this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {

		if ( material.visible === false ) return;

		updateObject( object );

		var program = setProgram( camera, lights, fog, material, object );

		var attributes = program.attributes;

		var updateBuffers = false,
			wireframeBit = material.wireframe ? 1 : 0,
			geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit;

		if ( geometryProgram !== _currentGeometryProgram ) {

			_currentGeometryProgram = geometryProgram;
			updateBuffers = true;

		}

		if ( updateBuffers ) {

			state.initAttributes();

		}

		// vertices

		if ( ! material.morphTargets && attributes.position >= 0 ) {

			if ( updateBuffers ) {

				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );

				state.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 ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {

					var attribute = geometryGroup.__webglCustomAttributesList[ i ];

					if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {

						_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );

						state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );

						_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );

					}

				}

			}


			// colors

			if ( attributes.color >= 0 ) {

				if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) {

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );

					state.enableAttribute( attributes.color );

					_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );

				} else if ( material.defaultAttributeValues !== undefined ) {


					_gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );

				}

			}

			// normals

			if ( attributes.normal >= 0 ) {

				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );

				state.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 );

				state.enableAttribute( attributes.tangent );

				_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );

			}

			// uvs

			if ( attributes.uv >= 0 ) {

				if ( object.geometry.faceVertexUvs[ 0 ] ) {

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );

					state.enableAttribute( attributes.uv );

					_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );

				} else if ( material.defaultAttributeValues !== undefined ) {


					_gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );

				}

			}

			if ( attributes.uv2 >= 0 ) {

				if ( object.geometry.faceVertexUvs[ 1 ] ) {

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );

					state.enableAttribute( attributes.uv2 );

					_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );

				} else if ( material.defaultAttributeValues !== undefined ) {


					_gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );

				}

			}

			if ( material.skinning &&
				 attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {

				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );

				state.enableAttribute( attributes.skinIndex );

				_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );

				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );

				state.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 );

				state.enableAttribute( attributes.lineDistance );

				_gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );

			}

		}

		state.disableUnusedAttributes();

		// render mesh

		if ( object instanceof THREE.Mesh ) {

			var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;

			// wireframe

			if ( material.wireframe ) {

				state.setLineWidth( material.wireframeLinewidth * pixelRatio );

				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
				_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 );

			// triangles

			} else {

				if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
				_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 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 ) {

			var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;

			state.setLineWidth( material.linewidth * pixelRatio );

			_gl.drawArrays( mode, 0, geometryGroup.__webglLineCount );

			_this.info.render.calls ++;

		// render particles

		} else if ( object instanceof THREE.PointCloud ) {

			_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );

			_this.info.render.calls ++;
			_this.info.render.points += geometryGroup.__webglParticleCount;

		}

	};

	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 ] );

			state.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 );

			state.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;

			var attribute;

			while ( m < material.numSupportedMorphTargets && m < order.length ) {

				attribute = attributes[ 'morphTarget' + m ];

				if ( attribute >= 0 ) {

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );

					state.enableAttribute( attribute );

					_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );

				}

				attribute = attributes[ 'morphNormal' + m ];

				if ( attribute >= 0 && material.morphNormals ) {

					_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );

					state.enableAttribute( attribute );

					_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );

				}

				object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];

				m ++;

			}

		} else {

			// find the most influencing

			var activeInfluenceIndices = [];
			var influences = object.morphTargetInfluences;
			var morphTargets = object.geometry.morphTargets;

			if ( influences.length > morphTargets.length ) {

				console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' );
				influences.length = morphTargets.length;

			}

			for ( var i = 0, il = influences.length; i < il; i ++ ) {

				var influence = influences[ i ];

				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 attribute;

			for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) {

				if ( activeInfluenceIndices[ m ] ) {

					var influenceIndex = activeInfluenceIndices[ m ][ 1 ];

					attribute = attributes[ 'morphTarget' + m ];

					if ( attribute >= 0 ) {

						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );

						state.enableAttribute( attribute );

						_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );

					}

					attribute = attributes[ 'morphNormal' + m ];

					if ( attribute >= 0 && material.morphNormals ) {

						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );

						state.enableAttribute( attribute );

						_gl.vertexAttribPointer( attribute, 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;

				}

			}

		}

		// 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.object.renderOrder !== b.object.renderOrder ) {

			return a.object.renderOrder - b.object.renderOrder;

		} else if ( a.material.id !== b.material.id ) {

			return a.material.id - b.material.id;

		} else if ( a.z !== b.z ) {

			return a.z - b.z;

		} else {

			return a.id - b.id;

		}

	}

	function reversePainterSortStable ( a, b ) {

		if ( a.object.renderOrder !== b.object.renderOrder ) {

			return a.object.renderOrder - b.object.renderOrder;

		} 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 ) {

			THREE.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
			return;

		}

		var fog = scene.fog;

		// reset caching for this frame

		_currentGeometryProgram = '';
		_currentMaterialId = - 1;
		_currentCamera = null;
		_lightsNeedUpdate = true;

		// update scene graph

		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();

		// update camera matrices and frustum

		if ( camera.parent === undefined ) camera.updateMatrixWorld();

		// update Skeleton objects

		scene.traverse( function ( object ) {

			if ( object instanceof THREE.SkinnedMesh ) {

				object.skeleton.update();

			}

		} );

		camera.matrixWorldInverse.getInverse( camera.matrixWorld );

		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
		_frustum.setFromMatrix( _projScreenMatrix );

		lights.length = 0;
		opaqueObjects.length = 0;
		transparentObjects.length = 0;

		sprites.length = 0;
		lensFlares.length = 0;

		projectObject( scene );

		if ( _this.sortObjects === true ) {

			opaqueObjects.sort( painterSortStable );
			transparentObjects.sort( reversePainterSortStable );

		}

		// custom render plugins (pre pass)

		shadowMapPlugin.render( 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 immediate objects

		for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) {

			var webglObject = _webglObjectsImmediate[ i ];
			var object = webglObject.object;

			if ( object.visible ) {

				setupMatrices( object, camera );

				unrollImmediateBufferMaterial( webglObject );

			}

		}

		if ( scene.overrideMaterial ) {

			var overrideMaterial = scene.overrideMaterial;

			setMaterial( overrideMaterial );

			renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial );
			renderObjects( transparentObjects, camera, lights, fog, overrideMaterial );
			renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial );

		} else {

			// opaque pass (front-to-back order)

			state.setBlending( THREE.NoBlending );

			renderObjects( opaqueObjects, camera, lights, fog, null );
			renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null );

			// transparent pass (back-to-front order)

			renderObjects( transparentObjects, camera, lights, fog, null );
			renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null );

		}

		// custom render plugins (post pass)

		spritePlugin.render( scene, camera );
		lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight );

		// 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

		state.setDepthTest( true );
		state.setDepthWrite( true );
		state.setColorWrite( true );

		// _gl.finish();

	};

	function projectObject( object ) {

		if ( object.visible === false ) return;

		if ( object instanceof THREE.Scene || object instanceof THREE.Group ) {

			// skip

		} else {

			initObject( object );

			if ( object instanceof THREE.Light ) {

				lights.push( object );

			} else if ( object instanceof THREE.Sprite ) {

				sprites.push( object );

			} else if ( object instanceof THREE.LensFlare ) {

				lensFlares.push( object );

			} else {

				var webglObjects = _webglObjects[ object.id ];

				if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {

					for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {

						var webglObject = webglObjects[ i ];

						unrollBufferMaterial( webglObject );

						webglObject.render = true;

						if ( _this.sortObjects === true ) {

							_vector3.setFromMatrixPosition( object.matrixWorld );
							_vector3.applyProjection( _projScreenMatrix );

							webglObject.z = _vector3.z;

						}

					}

				}

			}

		}

		for ( var i = 0, l = object.children.length; i < l; i ++ ) {

			projectObject( object.children[ i ] );

		}

	}

	function renderObjects( renderList, camera, lights, fog, overrideMaterial ) {

		var material;

		for ( var i = 0, l = renderList.length; i < l; i ++ ) {

			var webglObject = renderList[ i ];

			var object = webglObject.object;
			var buffer = webglObject.buffer;

			setupMatrices( object, camera );

			if ( overrideMaterial ) {

				material = overrideMaterial;

			} else {

				material = webglObject.material;

				if ( ! material ) continue;

				setMaterial( material );

			}

			_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, overrideMaterial ) {

		var material;

		for ( var i = 0, l = renderList.length; i < l; i ++ ) {

			var webglObject = renderList[ i ];
			var object = webglObject.object;

			if ( object.visible ) {

				if ( overrideMaterial ) {

					material = overrideMaterial;

				} else {

					material = webglObject[ materialType ];

					if ( ! material ) continue;

					setMaterial( material );

				}

				_this.renderImmediateObject( camera, lights, fog, material, object );

			}

		}

	}

	this.renderImmediateObject = function ( camera, lights, fog, material, object ) {

		var program = setProgram( camera, lights, fog, material, object );

		_currentGeometryProgram = '';

		_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;
		var buffer = globject.buffer;

		var geometry = object.geometry;
		var material = object.material;

		if ( material instanceof THREE.MeshFaceMaterial ) {

			var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex;

			material = material.materials[ materialIndex ];

			globject.material = material;

			if ( material.transparent ) {

				transparentObjects.push( globject );

			} else {

				opaqueObjects.push( globject );

			}

		} else if ( material ) {

			globject.material = material;

			if ( material.transparent ) {

				transparentObjects.push( globject );

			} else {

				opaqueObjects.push( globject );

			}

		}

	}

	function initObject( object ) {

		if ( object.__webglInit === undefined ) {

			object.__webglInit = true;
			object._modelViewMatrix = new THREE.Matrix4();
			object._normalMatrix = new THREE.Matrix3();

			object.addEventListener( 'removed', onObjectRemoved );

		}

		var geometry = object.geometry;

		if ( geometry === undefined ) {

			// ImmediateRenderObject

		} else if ( geometry.__webglInit === undefined ) {

			geometry.__webglInit = true;
			geometry.addEventListener( 'dispose', onGeometryDispose );

			if ( geometry instanceof THREE.BufferGeometry ) {

				_this.info.memory.geometries ++;

			} else if ( object instanceof THREE.Mesh ) {

				initGeometryGroups( object, geometry );

			} else if ( object instanceof THREE.Line ) {

				if ( geometry.__webglVertexBuffer === undefined ) {

					createLineBuffers( geometry );
					initLineBuffers( geometry, object );

					geometry.verticesNeedUpdate = true;
					geometry.colorsNeedUpdate = true;
					geometry.lineDistancesNeedUpdate = true;

				}

			} else if ( object instanceof THREE.PointCloud ) {

				if ( geometry.__webglVertexBuffer === undefined ) {

					createParticleBuffers( geometry );
					initParticleBuffers( geometry, object );

					geometry.verticesNeedUpdate = true;
					geometry.colorsNeedUpdate = true;

				}

			}

		}

		if ( object.__webglActive === undefined) {

			object.__webglActive = true;

			if ( object instanceof THREE.Mesh ) {

				if ( geometry instanceof THREE.BufferGeometry ) {

					addBuffer( _webglObjects, geometry, object );

				} else if ( geometry instanceof THREE.Geometry ) {

					var geometryGroupsList = geometryGroups[ geometry.id ];

					for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) {

						addBuffer( _webglObjects, geometryGroupsList[ i ], object );

					}

				}

			} else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) {

				addBuffer( _webglObjects, geometry, object );

			} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {

				addBufferImmediate( _webglObjectsImmediate, object );

			}

		}

	}

	// Geometry splitting

	var geometryGroups = {};
	var geometryGroupCounter = 0;

	function makeGroups( geometry, usesFaceMaterial ) {

		var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535;

		var groupHash, hash_map = {};

		var numMorphTargets = geometry.morphTargets.length;
		var numMorphNormals = geometry.morphNormals.length;

		var group;
		var groups = {};
		var groupsList = [];

		for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

			var face = geometry.faces[ f ];
			var materialIndex = usesFaceMaterial ? face.materialIndex : 0;

			if ( ! ( materialIndex in hash_map ) ) {

				hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 };

			}

			groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;

			if ( ! ( groupHash in groups ) ) {

				group = {
					id: geometryGroupCounter ++,
					faces3: [],
					materialIndex: materialIndex,
					vertices: 0,
					numMorphTargets: numMorphTargets,
					numMorphNormals: numMorphNormals
				};

				groups[ groupHash ] = group;
				groupsList.push( group );

			}

			if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {

				hash_map[ materialIndex ].counter += 1;
				groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;

				if ( ! ( groupHash in groups ) ) {

					group = {
						id: geometryGroupCounter ++,
						faces3: [],
						materialIndex: materialIndex,
						vertices: 0,
						numMorphTargets: numMorphTargets,
						numMorphNormals: numMorphNormals
					};

					groups[ groupHash ] = group;
					groupsList.push( group );

				}

			}

			groups[ groupHash ].faces3.push( f );
			groups[ groupHash ].vertices += 3;

		}

		return groupsList;

	}

	function initGeometryGroups( object, geometry ) {

		var material = object.material, addBuffers = false;

		if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) {

			delete _webglObjects[ object.id ];

			geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial );

			geometry.groupsNeedUpdate = false;

		}

		var geometryGroupsList = geometryGroups[ geometry.id ];

		// create separate VBOs per geometry chunk

		for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {

			var geometryGroup = geometryGroupsList[ i ];

			// initialise VBO on the first access

			if ( geometryGroup.__webglVertexBuffer === undefined ) {

				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;

				addBuffers = true;

			} else {

				addBuffers = false;

			}

			if ( addBuffers || object.__webglActive === undefined ) {

				addBuffer( _webglObjects, geometryGroup, object );

			}

		}

		object.__webglActive = true;

	}

	function addBuffer( objlist, buffer, object ) {

		var id = object.id;
		objlist[id] = objlist[id] || [];
		objlist[id].push(
			{
				id: id,
				buffer: buffer,
				object: object,
				material: null,
				z: 0
			}
		);

	};

	function addBufferImmediate( objlist, object ) {

		objlist.push(
			{
				id: null,
				object: object,
				opaque: null,
				transparent: null,
				z: 0
			}
		);

	};

	// Objects updates

	function updateObject( object ) {

		var geometry = object.geometry;

		if ( geometry instanceof THREE.BufferGeometry ) {

			var attributes = geometry.attributes;
			var attributesKeys = geometry.attributesKeys;

			for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) {

				var key = attributesKeys[ i ];
				var attribute = attributes[ key ];
				var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;

				if ( attribute.buffer === undefined ) {

					attribute.buffer = _gl.createBuffer();
					_gl.bindBuffer( bufferType, attribute.buffer );
					_gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW );

					attribute.needsUpdate = false;

				} else if ( attribute.needsUpdate === true ) {

					_gl.bindBuffer( bufferType, attribute.buffer );

					if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges

						_gl.bufferSubData( bufferType, 0, attribute.array );

					} else if ( attribute.updateRange.count === 0 ) {

						console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' );

					} else {

						_gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT,
										   attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) );

						attribute.updateRange.count = 0; // reset range

					}

					attribute.needsUpdate = false;

				}

			}

		} else if ( object instanceof THREE.Mesh ) {

			// check all geometry groups

			if ( geometry.groupsNeedUpdate === true ) {

				initGeometryGroups( object, geometry );

			}

			var geometryGroupsList = geometryGroups[ geometry.id ];

			for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {

				var geometryGroup = geometryGroupsList[ i ];
				var material = getBufferMaterial( object, geometryGroup );

				var 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;

			material.attributes && clearCustomAttributes( material );

		} else if ( object instanceof THREE.Line ) {

			var material = getBufferMaterial( object, geometry );
			var 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.PointCloud ) {

			var material = getBufferMaterial( object, geometry );
			var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );

			if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || 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 name in material.attributes ) {

			if ( material.attributes[ name ].needsUpdate ) return true;

		}

		return false;

	}

	function clearCustomAttributes( material ) {

		for ( var name in material.attributes ) {

			material.attributes[ name ].needsUpdate = false;

		}

	}

	// Objects removal

	function removeObject( object ) {

		if ( object instanceof THREE.Mesh  ||
			 object instanceof THREE.PointCloud ||
			 object instanceof THREE.Line ) {

			delete _webglObjects[ object.id ];

		} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {

			removeInstances( _webglObjectsImmediate, object );

		}

		delete object.__webglInit;
		delete object._modelViewMatrix;
		delete object._normalMatrix;

		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 );

			}

		}

	}

	// Materials

	var shaderIDs = {
		MeshDepthMaterial: 'depth',
		MeshNormalMaterial: 'normal',
		MeshBasicMaterial: 'basic',
		MeshLambertMaterial: 'lambert',
		MeshPhongMaterial: 'phong',
		LineBasicMaterial: 'basic',
		LineDashedMaterial: 'dashed',
		PointCloudMaterial: 'particle_basic'
	};

	function initMaterial( material, lights, fog, object ) {

		material.addEventListener( 'dispose', onMaterialDispose );

		var shaderID = shaderIDs[ material.type ];

		if ( shaderID ) {

			var shader = THREE.ShaderLib[ shaderID ];

			material.__webglShader = {
				uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
				vertexShader: shader.vertexShader,
				fragmentShader: shader.fragmentShader
			}

		} else {

			material.__webglShader = {
				uniforms: material.uniforms,
				vertexShader: material.vertexShader,
				fragmentShader: material.fragmentShader
			}

		}

		// heuristics to create shader parameters according to lights in the scene
		// (not to blow over maxLights budget)

		var maxLightCount = allocateLights( lights );
		var maxShadows = allocateShadows( lights );
		var maxBones = allocateBones( object );

		var parameters = {

			precision: _precision,
			supportsVertexTextures: _supportsVertexTextures,

			map: !! material.map,
			envMap: !! material.envMap,
			envMapMode: material.envMap && material.envMap.mapping,
			lightMap: !! material.lightMap,
			bumpMap: !! material.bumpMap,
			normalMap: !! material.normalMap,
			specularMap: !! material.specularMap,
			alphaMap: !! material.alphaMap,

			combine: material.combine,

			vertexColors: material.vertexColors,

			fog: fog,
			useFog: material.fog,
			fogExp: fog instanceof THREE.FogExp2,

			flatShading: material.shading === THREE.FlatShading,

			sizeAttenuation: material.sizeAttenuation,
			logarithmicDepthBuffer: _logarithmicDepthBuffer,

			skinning: material.skinning,
			maxBones: maxBones,
			useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture,

			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 && maxShadows > 0,
			shadowMapType: _this.shadowMapType,
			shadowMapDebug: _this.shadowMapDebug,
			shadowMapCascade: _this.shadowMapCascade,

			alphaTest: material.alphaTest,
			metal: material.metal,
			wrapAround: material.wrapAround,
			doubleSided: material.side === THREE.DoubleSide,
			flipSided: material.side === THREE.BackSide

		};

		// Generate code

		var chunks = [];

		if ( shaderID ) {

			chunks.push( shaderID );

		} else {

			chunks.push( material.fragmentShader );
			chunks.push( material.vertexShader );

		}

		if ( material.defines !== undefined ) {

			for ( var name in material.defines ) {

				chunks.push( name );
				chunks.push( material.defines[ name ] );

			}

		}

		for ( var name in parameters ) {

			chunks.push( name );
			chunks.push( parameters[ name ] );

		}

		var code = chunks.join();

		var program;

		// Check if code has been already compiled

		for ( var p = 0, pl = _programs.length; p < pl; p ++ ) {

			var programInfo = _programs[ p ];

			if ( programInfo.code === code ) {

				program = programInfo;
				program.usedTimes ++;

				break;

			}

		}

		if ( program === undefined ) {

			program = new THREE.WebGLProgram( _this, code, material, parameters );
			_programs.push( program );

			_this.info.memory.programs = _programs.length;

		}

		material.program = program;

		var attributes = program.attributes;

		if ( material.morphTargets ) {

			material.numSupportedMorphTargets = 0;

			var id, base = 'morphTarget';

			for ( var 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 ( var u in material.__webglShader.uniforms ) {

			var location = material.program.uniforms[ u ];

			if ( location ) {
				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
			}

		}

	}

	function setMaterial( material ) {

		if ( material.transparent === true ) {

			state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha );

		} else {

			state.setBlending( THREE.NoBlending );

		}

		state.setDepthTest( material.depthTest );
		state.setDepthWrite( material.depthWrite );
		state.setColorWrite( material.colorWrite );
		state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

	}

	function setProgram( camera, lights, fog, material, object ) {

		_usedTextureUnits = 0;

		if ( material.needsUpdate ) {

			if ( material.program ) deallocateMaterial( material );
			initMaterial( material, lights, fog, object );
			material.needsUpdate = false;

		}

		if ( material.morphTargets ) {

			if ( ! object.__webglMorphTargetInfluences ) {

				object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );

			}

		}

		var refreshProgram = false;
		var refreshMaterial = false;
		var refreshLights = false;

		var program = material.program,
			p_uniforms = program.uniforms,
			m_uniforms = material.__webglShader.uniforms;

		if ( program.id !== _currentProgram ) {

			_gl.useProgram( program.program );
			_currentProgram = program.id;

			refreshProgram = true;
			refreshMaterial = true;
			refreshLights = true;

		}

		if ( material.id !== _currentMaterialId ) {

			if ( _currentMaterialId === -1 ) refreshLights = true;
			_currentMaterialId = material.id;

			refreshMaterial = true;

		}

		if ( refreshProgram || camera !== _currentCamera ) {

			_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );

			if ( _logarithmicDepthBuffer ) {

				_gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );

			}


			if ( camera !== _currentCamera ) _currentCamera = camera;

			// 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.setFromMatrixPosition( 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.MeshBasicMaterial ||
				 material instanceof THREE.ShaderMaterial ||
				 material.skinning ) {

				if ( p_uniforms.viewMatrix !== null ) {

					_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );

				}

			}

		}

		// 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 ( object.bindMatrix && p_uniforms.bindMatrix !== null ) {

				_gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements );

			}

			if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) {

				_gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements );

			}

			if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) {

				if ( p_uniforms.boneTexture !== null ) {

					var textureUnit = getTextureUnit();

					_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
					_this.setTexture( object.skeleton.boneTexture, textureUnit );

				}

				if ( p_uniforms.boneTextureWidth !== null ) {

					_gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth );

				}

				if ( p_uniforms.boneTextureHeight !== null ) {

					_gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight );

				}

			} else if ( object.skeleton && object.skeleton.boneMatrices ) {

				if ( p_uniforms.boneGlobalMatrices !== null ) {

					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.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 ) {

					refreshLights = true;
					setupLights( lights );
					_lightsNeedUpdate = false;
				}

				if ( refreshLights ) {
					refreshUniformsLights( m_uniforms, _lights );
					markUniformsLightsNeedsUpdate(m_uniforms, true);
				} else {
				    markUniformsLightsNeedsUpdate(m_uniforms, false);
				}

			}

			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.PointCloudMaterial ) {

				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( material.uniformsList );

		}

		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;

		uniforms.diffuse.value = material.color;

		uniforms.map.value = material.map;
		uniforms.lightMap.value = material.lightMap;
		uniforms.specularMap.value = material.specularMap;
		uniforms.alphaMap.value = material.alphaMap;

		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
		//  5. alpha 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;

		} else if ( material.alphaMap ) {

			uvScaleMap = material.alphaMap;

		}

		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;

		uniforms.reflectivity.value = material.reflectivity;
		uniforms.refractionRatio.value = material.refractionRatio;

	}

	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;

		if ( material.map !== null ) {

			var offset = material.map.offset;
			var repeat = material.map.repeat;

			uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

		}

	}

	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;

		uniforms.emissive.value = material.emissive;
		uniforms.specular.value = material.specular;

		if ( material.wrapAround ) {

			uniforms.wrapRGB.value.copy( material.wrapRGB );

		}

	}

	function refreshUniformsLambert ( uniforms, material ) {

		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.pointLightDecay.value = lights.point.decays;

		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.spotLightDecay.value = lights.spot.decays;

		uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
		uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
		uniforms.hemisphereLightDirection.value = lights.hemi.positions;

	}

	// If uniforms are marked as clean, they don't need to be loaded to the GPU.

	function markUniformsLightsNeedsUpdate ( uniforms, value ) {

		uniforms.ambientLightColor.needsUpdate = value;

		uniforms.directionalLightColor.needsUpdate = value;
		uniforms.directionalLightDirection.needsUpdate = value;

		uniforms.pointLightColor.needsUpdate = value;
		uniforms.pointLightPosition.needsUpdate = value;
		uniforms.pointLightDistance.needsUpdate = value;
		uniforms.pointLightDecay.needsUpdate = value;

		uniforms.spotLightColor.needsUpdate = value;
		uniforms.spotLightPosition.needsUpdate = value;
		uniforms.spotLightDistance.needsUpdate = value;
		uniforms.spotLightDirection.needsUpdate = value;
		uniforms.spotLightAngleCos.needsUpdate = value;
		uniforms.spotLightExponent.needsUpdate = value;
		uniforms.spotLightDecay.needsUpdate = value;

		uniforms.hemisphereLightSkyColor.needsUpdate = value;
		uniforms.hemisphereLightGroundColor.needsUpdate = value;
		uniforms.hemisphereLightDirection.needsUpdate = value;

	}

	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 ) {

			THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures );

		}

		_usedTextureUnits += 1;

		return textureUnit;

	}

	function loadUniformsGeneric ( uniforms ) {

		var texture, textureUnit, offset;

		for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) {

			var uniform = uniforms[ j ][ 0 ];

			// needsUpdate property is not added to all uniforms.
			if ( uniform.needsUpdate === false ) continue;

			var type = uniform.type;
			var value = uniform.value;
			var location = uniforms[ j ][ 1 ];

			switch ( type ) {

				case '1i':
					_gl.uniform1i( location, value );
					break;

				case '1f':
					_gl.uniform1f( location, value );
					break;

				case '2f':
					_gl.uniform2f( location, value[ 0 ], value[ 1 ] );
					break;

				case '3f':
					_gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] );
					break;

				case '4f':
					_gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] );
					break;

				case '1iv':
					_gl.uniform1iv( location, value );
					break;

				case '3iv':
					_gl.uniform3iv( location, value );
					break;

				case '1fv':
					_gl.uniform1fv( location, value );
					break;

				case '2fv':
					_gl.uniform2fv( location, value );
					break;

				case '3fv':
					_gl.uniform3fv( location, value );
					break;

				case '4fv':
					_gl.uniform4fv( location, value );
					break;

				case 'Matrix3fv':
					_gl.uniformMatrix3fv( location, false, value );
					break;

				case 'Matrix4fv':
					_gl.uniformMatrix4fv( location, false, value );
					break;

				//

				case 'i':

					// single integer
					_gl.uniform1i( location, value );

					break;

				case 'f':

					// single float
					_gl.uniform1f( location, value );

					break;

				case 'v2':

					// single THREE.Vector2
					_gl.uniform2f( location, value.x, value.y );

					break;

				case 'v3':

					// single THREE.Vector3
					_gl.uniform3f( location, value.x, value.y, value.z );

					break;

				case 'v4':

					// single THREE.Vector4
					_gl.uniform4f( location, value.x, value.y, value.z, value.w );

					break;

				case 'c':

					// single THREE.Color
					_gl.uniform3f( location, value.r, value.g, value.b );

					break;

				case 'iv1':

					// flat array of integers (JS or typed array)
					_gl.uniform1iv( location, value );

					break;

				case 'iv':

					// flat array of integers with 3 x N size (JS or typed array)
					_gl.uniform3iv( location, value );

					break;

				case 'fv1':

					// flat array of floats (JS or typed array)
					_gl.uniform1fv( location, value );

					break;

				case 'fv':

					// flat array of floats with 3 x N size (JS or typed array)
					_gl.uniform3fv( location, value );

					break;

				case 'v2v':

					// array of THREE.Vector2

					if ( uniform._array === undefined ) {

						uniform._array = new Float32Array( 2 * value.length );

					}

					for ( var 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 );

					break;

				case 'v3v':

					// array of THREE.Vector3

					if ( uniform._array === undefined ) {

						uniform._array = new Float32Array( 3 * value.length );

					}

					for ( var 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 );

					break;

				case 'v4v':

					// array of THREE.Vector4

					if ( uniform._array === undefined ) {

						uniform._array = new Float32Array( 4 * value.length );

					}

					for ( var 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 );

					break;

				case 'm3':

					// single THREE.Matrix3
					_gl.uniformMatrix3fv( location, false, value.elements );

					break;

				case 'm3v':

					// array of THREE.Matrix3

					if ( uniform._array === undefined ) {

						uniform._array = new Float32Array( 9 * value.length );

					}

					for ( var i = 0, il = value.length; i < il; i ++ ) {

						value[ i ].flattenToArrayOffset( uniform._array, i * 9 );

					}

					_gl.uniformMatrix3fv( location, false, uniform._array );

					break;

				case 'm4':

					// single THREE.Matrix4
					_gl.uniformMatrix4fv( location, false, value.elements );

					break;

				case 'm4v':

					// array of THREE.Matrix4

					if ( uniform._array === undefined ) {

						uniform._array = new Float32Array( 16 * value.length );

					}

					for ( var i = 0, il = value.length; i < il; i ++ ) {

						value[ i ].flattenToArrayOffset( uniform._array, i * 16 );

					}

					_gl.uniformMatrix4fv( location, false, uniform._array );

					break;

				case 't':

					// single THREE.Texture (2d or cube)

					texture = value;
					textureUnit = getTextureUnit();

					_gl.uniform1i( location, textureUnit );

					if ( ! texture ) continue;

					if ( texture instanceof THREE.CubeTexture ||
					   ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/

						setCubeTexture( texture, textureUnit );

					} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {

						setCubeTextureDynamic( texture, textureUnit );

					} else {

						_this.setTexture( texture, textureUnit );

					}

					break;

				case 'tv':

					// array of THREE.Texture (2d)

					if ( uniform._array === undefined ) {

						uniform._array = [];

					}

					for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {

						uniform._array[ i ] = getTextureUnit();

					}

					_gl.uniform1iv( location, uniform._array );

					for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {

						texture = uniform.value[ i ];
						textureUnit = uniform._array[ i ];

						if ( ! texture ) continue;

						_this.setTexture( texture, textureUnit );

					}

					break;

				default:

					THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type );

			}

		}

	}

	function setupMatrices ( object, camera ) {

		object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
		object._normalMatrix.getNormalMatrix( object._modelViewMatrix );

	}

	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 ( lights ) {

		var l, ll, light,
		r = 0, g = 0, b = 0,
		color, skyColor, groundColor,
		intensity,
		distance,

		zlights = _lights,

		dirColors = zlights.directional.colors,
		dirPositions = zlights.directional.positions,

		pointColors = zlights.point.colors,
		pointPositions = zlights.point.positions,
		pointDistances = zlights.point.distances,
		pointDecays = zlights.point.decays,

		spotColors = zlights.spot.colors,
		spotPositions = zlights.spot.positions,
		spotDistances = zlights.spot.distances,
		spotDirections = zlights.spot.directions,
		spotAnglesCos = zlights.spot.anglesCos,
		spotExponents = zlights.spot.exponents,
		spotDecays = zlights.spot.decays,

		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;

				r += color.r;
				g += color.g;
				b += color.b;

			} else if ( light instanceof THREE.DirectionalLight ) {

				dirCount += 1;

				if ( ! light.visible ) continue;

				_direction.setFromMatrixPosition( light.matrixWorld );
				_vector3.setFromMatrixPosition( light.target.matrixWorld );
				_direction.sub( _vector3 );
				_direction.normalize();

				dirOffset = dirLength * 3;

				dirPositions[ dirOffset ]     = _direction.x;
				dirPositions[ dirOffset + 1 ] = _direction.y;
				dirPositions[ dirOffset + 2 ] = _direction.z;

				setColorLinear( dirColors, dirOffset, color, intensity );

				dirLength += 1;

			} else if ( light instanceof THREE.PointLight ) {

				pointCount += 1;

				if ( ! light.visible ) continue;

				pointOffset = pointLength * 3;

				setColorLinear( pointColors, pointOffset, color, intensity );

				_vector3.setFromMatrixPosition( light.matrixWorld );

				pointPositions[ pointOffset ]     = _vector3.x;
				pointPositions[ pointOffset + 1 ] = _vector3.y;
				pointPositions[ pointOffset + 2 ] = _vector3.z;

				// distance is 0 if decay is 0, because there is no attenuation at all.
				pointDistances[ pointLength ] = distance;
				pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;

				pointLength += 1;

			} else if ( light instanceof THREE.SpotLight ) {

				spotCount += 1;

				if ( ! light.visible ) continue;

				spotOffset = spotLength * 3;

				setColorLinear( spotColors, spotOffset, color, intensity );

				_direction.setFromMatrixPosition( light.matrixWorld );

				spotPositions[ spotOffset ]     = _direction.x;
				spotPositions[ spotOffset + 1 ] = _direction.y;
				spotPositions[ spotOffset + 2 ] = _direction.z;

				spotDistances[ spotLength ] = distance;

				_vector3.setFromMatrixPosition( 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;
				spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;

				spotLength += 1;

			} else if ( light instanceof THREE.HemisphereLight ) {

				hemiCount += 1;

				if ( ! light.visible ) continue;

				_direction.setFromMatrixPosition( light.matrixWorld );
				_direction.normalize();

				hemiOffset = hemiLength * 3;

				hemiPositions[ hemiOffset ]     = _direction.x;
				hemiPositions[ hemiOffset + 1 ] = _direction.y;
				hemiPositions[ hemiOffset + 2 ] = _direction.z;

				skyColor = light.color;
				groundColor = light.groundColor;

				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 ) {

		state.setDoubleSided( material.side === THREE.DoubleSide );
		state.setFlipSided( material.side === THREE.BackSide );

	};

	// Textures

	function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {

		var extension;

		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 );

			if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) {

				THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' );

			}

			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );

			if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) {

				THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' );

			}

		}

		extension = extensions.get( 'EXT_texture_filter_anisotropic' );

		if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {

			if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) {

				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
				texture.__currentAnisotropy = texture.anisotropy;

			}

		}

	}

	this.uploadTexture = function ( texture ) {

		if ( texture.__webglInit === undefined ) {

			texture.__webglInit = true;

			texture.addEventListener( 'dispose', onTextureDispose );

			texture.__webglTexture = _gl.createTexture();

			_this.info.memory.textures ++;

		}

		_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 );

		texture.image = clampToMaxSize( texture.image, _maxTextureSize );

		var image = texture.image,
		isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.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 ) {

			for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

				mipmap = mipmaps[ i ];

				if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {

					if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {

						_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

					} else {

						THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" );

					}

				} else {

					_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, 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();

	};

	this.setTexture = function ( texture, slot ) {

		_gl.activeTexture( _gl.TEXTURE0 + slot );

		if ( texture.needsUpdate ) {

			_this.uploadTexture( texture );

		} else {

			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );

		}

	};

	function clampToMaxSize ( image, maxSize ) {

		if ( image.width > maxSize || image.height > maxSize ) {

			// Warning: Scaling through the canvas will only work with images that use
			// premultiplied alpha.

			var scale = maxSize / Math.max( image.width, image.height );

			var canvas = document.createElement( 'canvas' );
			canvas.width = Math.floor( image.width * scale );
			canvas.height = Math.floor( image.height * scale );

			var context = canvas.getContext( '2d' );
			context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );

			THREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );

			return canvas;

		}

		return image;

	}

	function setCubeTexture ( texture, slot ) {

		if ( texture.image.length === 6 ) {

			if ( texture.needsUpdate ) {

				if ( ! texture.image.__webglTextureCube ) {

					texture.addEventListener( 'dispose', onTextureDispose );

					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 isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture;

				var cubeImage = [];

				for ( var i = 0; i < 6; i ++ ) {

					if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) {

						cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );

					} else {

						cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];

					}

				}

				var image = cubeImage[ 0 ],
				isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.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 ) {

						if ( isDataTexture ) {

							_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );

						} else {

							_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );

						}

					} else {

						var mipmap, mipmaps = cubeImage[ i ].mipmaps;

						for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {

							mipmap = mipmaps[ j ];

							if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {

								if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {

									_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

								} else {

									THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" );

								}

							} else {

								_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

							}

						}

					}

				}

				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 === undefined ) {

			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 = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.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;

	};

	this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) {

		if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) {

			console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
			return;

		}

		if ( renderTarget.__webglFramebuffer ) {

			if ( renderTarget.format !== THREE.RGBAFormat ) {

				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' );
				return;

			}

			var restore = false;

			if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) {

				_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer );

				restore = true;

			}

			if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {

				_gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer );

			} else {

				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );

			}

			if ( restore ) {

				_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );

			}

		}

	};

	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 ) {

		var extension;

		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;

		extension = extensions.get( 'OES_texture_half_float' );

		if ( extension !== null ) {

			if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES;

		}

		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;

		extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );

		if ( extension !== null ) {

			if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
			if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
			if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
			if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;

		}

		extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );

		if ( extension !== null ) {

			if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
			if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
			if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
			if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;

		}

		extension = extensions.get( 'EXT_blend_minmax' );

		if ( extension !== null ) {

			if ( p === THREE.MinEquation ) return extension.MIN_EXT;
			if ( p === THREE.MaxEquation ) return extension.MAX_EXT;

		}

		return 0;

	}

	// Allocations

	function allocateBones ( object ) {

		if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.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.skeleton.bones.length, maxBones );

				if ( maxBones < object.skeleton.bones.length ) {

					THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );

				}

			}

			return maxBones;

		}

	}

	function allocateLights( lights ) {

		var dirLights = 0;
		var pointLights = 0;
		var spotLights = 0;
		var hemiLights = 0;

		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {

			var light = lights[ l ];

			if ( light.onlyShadow || light.visible === false ) 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 maxShadows = 0;

		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {

			var light = lights[ l ];

			if ( ! light.castShadow ) continue;

			if ( light instanceof THREE.SpotLight ) maxShadows ++;
			if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;

		}

		return maxShadows;

	}

	// DEPRECATED

	this.initMaterial = function () {

		THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );

	};

	this.addPrePlugin = function () {

		THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );

	};

	this.addPostPlugin = function () {

		THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );

	};

	this.updateShadowMap = function () {

		THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );

	};

};

// File:src/renderers/WebGLRenderTarget.js

/**
 * @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 = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null;

};

THREE.WebGLRenderTarget.prototype = {

	constructor: THREE.WebGLRenderTarget,

	setSize: function (width, height) {

	    if (this.width !== width || this.height !== height) {

	        this.width = width;
	        this.height = height;

	        this.dispose();
	    }

	},

	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' } );

	}

};

THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype );

// File:src/renderers/WebGLRenderTargetCube.js

/**
 * @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 );
THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube;

// File:src/renderers/webgl/WebGLExtensions.js

/**
* @author mrdoob / http://mrdoob.com/
*/

THREE.WebGLExtensions = function ( gl ) {

	var extensions = {};

	this.get = function ( name ) {

		if ( extensions[ name ] !== undefined ) {

			return extensions[ name ];

		}

		var extension;

		switch ( name ) {

			case 'EXT_texture_filter_anisotropic':
				extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
				break;

			case 'WEBGL_compressed_texture_s3tc':
				extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
				break;

			case 'WEBGL_compressed_texture_pvrtc':
				extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
				break;

			default:
				extension = gl.getExtension( name );

		}

		if ( extension === null ) {

			THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );

		}

		extensions[ name ] = extension;

		return extension;

	};

};

// File:src/renderers/webgl/WebGLProgram.js

THREE.WebGLProgram = ( function () {

	var programIdCount = 0;

	var generateDefines = function ( 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' );

	};

	var cacheUniformLocations = function ( gl, program, identifiers ) {

		var uniforms = {};

		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {

			var id = identifiers[ i ];
			uniforms[ id ] = gl.getUniformLocation( program, id );

		}

		return uniforms;

	};

	var cacheAttributeLocations = function ( gl, program, identifiers ) {

		var attributes = {};

		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {

			var id = identifiers[ i ];
			attributes[ id ] = gl.getAttribLocation( program, id );

		}

		return attributes;

	};

	return function ( renderer, code, material, parameters ) {

		var _this = renderer;
		var _gl = _this.context;

		var defines = material.defines;
		var uniforms = material.__webglShader.uniforms;
		var attributes = material.attributes;

		var vertexShader = material.__webglShader.vertexShader;
		var fragmentShader = material.__webglShader.fragmentShader;

		var index0AttributeName = material.index0AttributeName;

		if ( index0AttributeName === undefined && parameters.morphTargets === true ) {

			// programs with morphTargets displace position out of attribute 0

			index0AttributeName = 'position';

		}

		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';

		}

		var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
		var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
		var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';

		if ( parameters.envMap ) {

			switch ( material.envMap.mapping ) {

				case THREE.CubeReflectionMapping:
				case THREE.CubeRefractionMapping:
					envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
					break;

				case THREE.EquirectangularReflectionMapping:
				case THREE.EquirectangularRefractionMapping:
					envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
					break;

				case THREE.SphericalReflectionMapping:
					envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
					break;

			}

			switch ( material.envMap.mapping ) {

				case THREE.CubeRefractionMapping:
				case THREE.EquirectangularRefractionMapping:
					envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
					break;

			}

			switch ( material.combine ) {

				case THREE.MultiplyOperation:
					envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
					break;

				case THREE.MixOperation:
					envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
					break;

				case THREE.AddOperation:
					envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
					break;

			}

		}

		var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;

		// console.log( 'building new program ' );

		//

		var customDefines = generateDefines( defines );

		//

		var program = _gl.createProgram();

		var prefix_vertex, prefix_fragment;

		if ( material instanceof THREE.RawShaderMaterial ) {

			prefix_vertex = '';
			prefix_fragment = '';

		} else {

			prefix_vertex = [

				'precision ' + parameters.precision + ' float;',
				'precision ' + parameters.precision + ' int;',

				customDefines,

				parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',

				_this.gammaInput ? '#define GAMMA_INPUT' : '',
				_this.gammaOutput ? '#define GAMMA_OUTPUT' : '',
				'#define GAMMA_FACTOR ' + gammaFactorDefine,

				'#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.envMap ? '#define ' + envMapModeDefine : '',
				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
				parameters.normalMap ? '#define USE_NORMALMAP' : '',
				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
				parameters.vertexColors ? '#define USE_COLOR' : '',

				parameters.flatShading ? '#define FLAT_SHADED': '',

				parameters.skinning ? '#define USE_SKINNING' : '',
				parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',

				parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
				parameters.morphNormals ? '#define USE_MORPHNORMALS' : '',
				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' : '',

				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
				//_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',


				'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' );

			prefix_fragment = [

				'precision ' + parameters.precision + ' float;',
				'precision ' + parameters.precision + ' int;',

				( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#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' : '',
				'#define GAMMA_FACTOR ' + gammaFactorDefine,

				( 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.envMap ? '#define ' + envMapTypeDefine : '',
				parameters.envMap ? '#define ' + envMapModeDefine : '',
				parameters.envMap ? '#define ' + envMapBlendingDefine : '',
				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
				parameters.normalMap ? '#define USE_NORMALMAP' : '',
				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
				parameters.vertexColors ? '#define USE_COLOR' : '',

				parameters.flatShading ? '#define FLAT_SHADED': '',

				parameters.metal ? '#define METAL' : '',
				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.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
				//_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',

				'uniform mat4 viewMatrix;',
				'uniform vec3 cameraPosition;',
				''

			].join( '\n' );

		}

		var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );
		var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );

		_gl.attachShader( program, glVertexShader );
		_gl.attachShader( program, glFragmentShader );

		if ( index0AttributeName !== undefined ) {

			// Force a particular attribute to index 0.
			// because potentially expensive emulation is done by browser if attribute 0 is disabled.
			// And, color, for example is often automatically bound to index 0 so disabling it

			_gl.bindAttribLocation( program, 0, index0AttributeName );

		}

		_gl.linkProgram( program );

		var programLogInfo = _gl.getProgramInfoLog( program );

		if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) {

			THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo );

		}

		if ( programLogInfo !== '' ) {

			//THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo );
			// THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
			// THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );

		}

		// clean up

		_gl.deleteShader( glVertexShader );
		_gl.deleteShader( glFragmentShader );

		// cache uniform locations

		var identifiers = [

			'viewMatrix',
			'modelViewMatrix',
			'projectionMatrix',
			'normalMatrix',
			'modelMatrix',
			'cameraPosition',
			'morphTargetInfluences',
			'bindMatrix',
			'bindMatrixInverse'

		];

		if ( parameters.useVertexTexture ) {

			identifiers.push( 'boneTexture' );
			identifiers.push( 'boneTextureWidth' );
			identifiers.push( 'boneTextureHeight' );

		} else {

			identifiers.push( 'boneGlobalMatrices' );

		}

		if ( parameters.logarithmicDepthBuffer ) {

			identifiers.push('logDepthBufFC');

		}


		for ( var u in uniforms ) {

			identifiers.push( u );

		}

		this.uniforms = cacheUniformLocations( _gl, program, identifiers );

		// cache attributes locations

		identifiers = [

			'position',
			'normal',
			'uv',
			'uv2',
			'tangent',
			'color',
			'skinIndex',
			'skinWeight',
			'lineDistance'

		];

		for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) {

			identifiers.push( 'morphTarget' + i );

		}

		for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) {

			identifiers.push( 'morphNormal' + i );

		}

		for ( var a in attributes ) {

			identifiers.push( a );

		}

		this.attributes = cacheAttributeLocations( _gl, program, identifiers );
		this.attributesKeys = Object.keys( this.attributes );

		//

		this.id = programIdCount ++;
		this.code = code;
		this.usedTimes = 1;
		this.program = program;
		this.vertexShader = glVertexShader;
		this.fragmentShader = glFragmentShader;

		return this;

	};

} )();

// File:src/renderers/webgl/WebGLShader.js

THREE.WebGLShader = ( function () {

	var addLineNumbers = function ( string ) {

		var lines = string.split( '\n' );

		for ( var i = 0; i < lines.length; i ++ ) {

			lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];

		}

		return lines.join( '\n' );

	};

	return function ( gl, type, string ) {

		var shader = gl.createShader( type ); 

		gl.shaderSource( shader, string );
		gl.compileShader( shader );

		if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {

			THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );

		}

		// if ( gl.getShaderInfoLog( shader ) !== '' ) {

		// 	THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );

		// }

		// --enable-privileged-webgl-extension
		// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );

		return shader;

	};

} )();

// File:src/renderers/webgl/WebGLState.js

/**
* @author mrdoob / http://mrdoob.com/
*/

THREE.WebGLState = function ( gl, paramThreeToGL ) {

	var newAttributes = new Uint8Array( 16 );
	var enabledAttributes = new Uint8Array( 16 );

	var currentBlending = null;
	var currentBlendEquation = null;
	var currentBlendSrc = null;
	var currentBlendDst = null;
	var currentBlendEquationAlpha = null;
	var currentBlendSrcAlpha = null;
	var currentBlendDstAlpha = null;

	var currentDepthTest = null;
	var currentDepthWrite = null;

	var currentColorWrite = null;

	var currentDoubleSided = null;
	var currentFlipSided = null;

	var currentLineWidth = null;

	var currentPolygonOffset = null;
	var currentPolygonOffsetFactor = null;
	var currentPolygonOffsetUnits = null;

	this.initAttributes = function () {

		for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {

			newAttributes[ i ] = 0;

		}

	};

	this.enableAttribute = function ( attribute ) {

		newAttributes[ attribute ] = 1;

		if ( enabledAttributes[ attribute ] === 0 ) {

			gl.enableVertexAttribArray( attribute );
			enabledAttributes[ attribute ] = 1;

		}

	};

	this.disableUnusedAttributes = function () {

		for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) {

			if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {

				gl.disableVertexAttribArray( i );
				enabledAttributes[ i ] = 0;

			}

		}

	};

	this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) {

		if ( blending !== currentBlending ) {

			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 );

			}

			currentBlending = blending;

		}

		if ( blending === THREE.CustomBlending ) {

			blendEquationAlpha = blendEquationAlpha || blendEquation;
			blendSrcAlpha = blendSrcAlpha || blendSrc;
			blendDstAlpha = blendDstAlpha || blendDst;

			if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {

				gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) );

				currentBlendEquation = blendEquation;
				currentBlendEquationAlpha = blendEquationAlpha;

			}

			if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {

				gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) );

				currentBlendSrc = blendSrc;
				currentBlendDst = blendDst;
				currentBlendSrcAlpha = blendSrcAlpha;
				currentBlendDstAlpha = blendDstAlpha;

			}

		} else {

			currentBlendEquation = null;
			currentBlendSrc = null;
			currentBlendDst = null;
			currentBlendEquationAlpha = null;
			currentBlendSrcAlpha = null;
			currentBlendDstAlpha = null;

		}

	};

	this.setDepthTest = function ( depthTest ) {

		if ( currentDepthTest !== depthTest ) {

			if ( depthTest ) {

				gl.enable( gl.DEPTH_TEST );

			} else {

				gl.disable( gl.DEPTH_TEST );

			}

			currentDepthTest = depthTest;

		}

	};

	this.setDepthWrite = function ( depthWrite ) {

		if ( currentDepthWrite !== depthWrite ) {

			gl.depthMask( depthWrite );
			currentDepthWrite = depthWrite;

		}

	};

	this.setColorWrite = function ( colorWrite ) {

		if ( currentColorWrite !== colorWrite ) {

			gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite );
			currentColorWrite = colorWrite;

		}

	};

	this.setDoubleSided = function ( doubleSided ) {

		if ( currentDoubleSided !== doubleSided ) {

			if ( doubleSided ) {

				gl.disable( gl.CULL_FACE );

			} else {

				gl.enable( gl.CULL_FACE );

			}

			currentDoubleSided = doubleSided;

		}

	};

	this.setFlipSided = function ( flipSided ) {

		if ( currentFlipSided !== flipSided ) {

			if ( flipSided ) {

				gl.frontFace( gl.CW );

			} else {

				gl.frontFace( gl.CCW );

			}

			currentFlipSided = flipSided;

		}

	};

	this.setLineWidth = function ( width ) {

		if ( width !== currentLineWidth ) {

			gl.lineWidth( width );

			currentLineWidth = width;

		}

	};

	this.setPolygonOffset = function ( polygonoffset, factor, units ) {

		if ( currentPolygonOffset !== polygonoffset ) {

			if ( polygonoffset ) {

				gl.enable( gl.POLYGON_OFFSET_FILL );

			} else {

				gl.disable( gl.POLYGON_OFFSET_FILL );

			}

			currentPolygonOffset = polygonoffset;

		}

		if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) {

			gl.polygonOffset( factor, units );

			currentPolygonOffsetFactor = factor;
			currentPolygonOffsetUnits = units;

		}

	};

	this.reset = function () {

		for ( var i = 0; i < enabledAttributes.length; i ++ ) {

			enabledAttributes[ i ] = 0;

		}

		currentBlending = null;
		currentDepthTest = null;
		currentDepthWrite = null;
		currentColorWrite = null;
		currentDoubleSided = null;
		currentFlipSided = null;

	};

};

// File:src/renderers/webgl/plugins/LensFlarePlugin.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.LensFlarePlugin = function ( renderer, flares ) {

	var gl = renderer.context;

	var vertexBuffer, elementBuffer;
	var program, attributes, uniforms;
	var hasVertexTexture;

	var tempTexture, occlusionTexture;

	var init = function () {

		var vertices = new Float32Array( [
			-1, -1,  0, 0,
			 1, -1,  1, 0,
			 1,  1,  1, 1,
			-1,  1,  0, 1
		] );

		var faces = new Uint16Array( [
			0, 1, 2,
			0, 2, 3
		] );

		// buffers

		vertexBuffer     = gl.createBuffer();
		elementBuffer    = gl.createBuffer();

		gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );

		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
		gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );

		// textures

		tempTexture      = gl.createTexture();
		occlusionTexture = gl.createTexture();

		gl.bindTexture( gl.TEXTURE_2D, 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, 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 );

		hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0;

		var shader;

		if ( hasVertexTexture ) {

			shader = {

				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 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );",
							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",

							"vVisibility =        visibility.r / 9.0;",
							"vVisibility *= 1.0 - visibility.g / 9.0;",
							"vVisibility *=       visibility.b / 9.0;",
							"vVisibility *= 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" )

			};

		} else {

			shader = {

				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;",
							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;",
							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;",
							"visibility += 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" )

			};

		}

		program = createProgram( shader );

		attributes = {
			vertex: gl.getAttribLocation ( program, "position" ),
			uv:     gl.getAttribLocation ( program, "uv" )
		}

		uniforms = {
			renderType:     gl.getUniformLocation( program, "renderType" ),
			map:            gl.getUniformLocation( program, "map" ),
			occlusionMap:   gl.getUniformLocation( program, "occlusionMap" ),
			opacity:        gl.getUniformLocation( program, "opacity" ),
			color:          gl.getUniformLocation( program, "color" ),
			scale:          gl.getUniformLocation( program, "scale" ),
			rotation:       gl.getUniformLocation( program, "rotation" ),
			screenPosition: gl.getUniformLocation( program, "screenPosition" )
		};

	};

	/*
	 * Render lens flares
	 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
	 *         reads these back and calculates occlusion.
	 */

	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {

		if ( flares.length === 0 ) 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 );

		if ( program === undefined ) {

			init();

		}

		gl.useProgram( program );

		gl.enableVertexAttribArray( attributes.vertex );
		gl.enableVertexAttribArray( 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, 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, elementBuffer );

		gl.disable( gl.CULL_FACE );
		gl.depthMask( false );

		for ( var i = 0, l = flares.length; i < l; i ++ ) {

			size = 16 / viewportHeight;
			scale.set( size * invAspect, size );

			// calc object screen position

			var 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 ( 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, 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, 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, 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 ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {

					var 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.state.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 );

		renderer.resetGLState();

	};

	function createProgram ( shader ) {

		var program = gl.createProgram();

		var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
		var vertexShader = gl.createShader( gl.VERTEX_SHADER );

		var prefix = "precision " + renderer.getPrecision() + " 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;

	}

};

// File:src/renderers/webgl/plugins/ShadowMapPlugin.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) {

	var _gl = _renderer.context;

	var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,

	_frustum = new THREE.Frustum(),
	_projScreenMatrix = new THREE.Matrix4(),

	_min = new THREE.Vector3(),
	_max = new THREE.Vector3(),

	_matrixPosition = new THREE.Vector3(),

	_renderList = [];

	// init

	var depthShader = THREE.ShaderLib[ "depthRGBA" ];
	var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

	_depthMaterial = new THREE.ShaderMaterial( {
		uniforms: depthUniforms,
		vertexShader: depthShader.vertexShader,
		fragmentShader: depthShader.fragmentShader
	 } );

	_depthMaterialMorph = new THREE.ShaderMaterial( {
		uniforms: depthUniforms,
		vertexShader: depthShader.vertexShader,
		fragmentShader: depthShader.fragmentShader,
		morphTargets: true
	} );

	_depthMaterialSkin = new THREE.ShaderMaterial( {
		uniforms: depthUniforms,
		vertexShader: depthShader.vertexShader,
		fragmentShader: depthShader.fragmentShader,
		skinning: true
	} );

	_depthMaterialMorphSkin = new THREE.ShaderMaterial( {
		uniforms: depthUniforms,
		vertexShader: depthShader.vertexShader,
		fragmentShader: depthShader.fragmentShader,
		morphTargets: true,
		skinning: true
	} );

	_depthMaterial._shadowPass = true;
	_depthMaterialMorph._shadowPass = true;
	_depthMaterialSkin._shadowPass = true;
	_depthMaterialMorphSkin._shadowPass = true;

	this.render = function ( scene, camera ) {

		if ( _renderer.shadowMapEnabled === false ) return;

		var i, il, j, jl, n,

		shadowMap, shadowMatrix, shadowCamera,
		buffer, material,
		webglObject, object, light,

		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.state.setDepthTest( true );

		// preprocess lights
		// 	- skip lights that are not casting shadows
		//	- create virtual lights for cascaded shadow maps

		for ( i = 0, il = _lights.length; i < il; i ++ ) {

			light = _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.copy( 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 {

					THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light );
					continue;

				}

				scene.add( light.shadowCamera );

				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();

			}

			if ( light.shadowCameraVisible && ! light.cameraHelper ) {

				light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
				scene.add( light.cameraHelper );

			}

			if ( light.isVirtual && virtualLight.originalCamera == camera ) {

				updateShadowCamera( camera, light );

			}

			shadowMap = light.shadowMap;
			shadowMatrix = light.shadowMatrix;
			shadowCamera = light.shadowCamera;

			//

			shadowCamera.position.setFromMatrixPosition( light.matrixWorld );
			_matrixPosition.setFromMatrixPosition( 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.length = 0;

			projectObject( scene, scene, shadowCamera );


			// render regular objects

			var objectMaterial, useMorphing, useSkinning;

			for ( j = 0, jl = _renderList.length; j < jl; j ++ ) {

				webglObject = _renderList[ j ];

				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 !== undefined && 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;

				}

				_renderer.setMaterialFaces( objectMaterial );

				if ( buffer instanceof THREE.BufferGeometry ) {

					_renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object );

				} else {

					_renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object );

				}

			}

			// set matrices and render immediate objects

			for ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) {

				webglObject = _webglObjectsImmediate[ j ];
				object = webglObject.object;

				if ( object.visible && object.castShadow ) {

					object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

					_renderer.renderImmediateObject( shadowCamera, _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 );

		}

		_renderer.resetGLState();

	};

	function projectObject( scene, object, shadowCamera ) {

		if ( object.visible ) {

			var webglObjects = _webglObjects[ object.id ];

			if ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) {

				for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {

					var webglObject = webglObjects[ i ];

					object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
					_renderList.push( webglObject );

				}

			}

			for ( var i = 0, l = object.children.length; i < l; i ++ ) {

				projectObject( scene, object.children[ i ], shadowCamera );

			}

		}

	}

	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 ] );
			p.unproject( 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;

	};

};

// File:src/renderers/webgl/plugins/SpritePlugin.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SpritePlugin = function ( renderer, sprites ) {

	var gl = renderer.context;

	var vertexBuffer, elementBuffer;
	var program, attributes, uniforms;

	var texture;

	// decompose matrixWorld

	var spritePosition = new THREE.Vector3();
	var spriteRotation = new THREE.Quaternion();
	var spriteScale = new THREE.Vector3();

	var init = function () {

		var vertices = new Float32Array( [
			- 0.5, - 0.5,  0, 0,
			  0.5, - 0.5,  1, 0,
			  0.5,   0.5,  1, 1,
			- 0.5,   0.5,  0, 1
		] );

		var faces = new Uint16Array( [
			0, 1, 2,
			0, 2, 3
		] );

		vertexBuffer  = gl.createBuffer();
		elementBuffer = gl.createBuffer();

		gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );

		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
		gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );

		program = createProgram();

		attributes = {
			position:			gl.getAttribLocation ( program, 'position' ),
			uv:					gl.getAttribLocation ( program, 'uv' )
		};

		uniforms = {
			uvOffset:			gl.getUniformLocation( program, 'uvOffset' ),
			uvScale:			gl.getUniformLocation( program, 'uvScale' ),

			rotation:			gl.getUniformLocation( program, 'rotation' ),
			scale:				gl.getUniformLocation( program, 'scale' ),

			color:				gl.getUniformLocation( program, 'color' ),
			map:				gl.getUniformLocation( program, 'map' ),
			opacity:			gl.getUniformLocation( program, 'opacity' ),

			modelViewMatrix: 	gl.getUniformLocation( program, 'modelViewMatrix' ),
			projectionMatrix:	gl.getUniformLocation( program, 'projectionMatrix' ),

			fogType:			gl.getUniformLocation( program, 'fogType' ),
			fogDensity:			gl.getUniformLocation( program, 'fogDensity' ),
			fogNear:			gl.getUniformLocation( program, 'fogNear' ),
			fogFar:				gl.getUniformLocation( program, 'fogFar' ),
			fogColor:			gl.getUniformLocation( program, 'fogColor' ),

			alphaTest:			gl.getUniformLocation( program, 'alphaTest' )
		};

		var canvas = document.createElement( 'canvas' );
		canvas.width = 8;
		canvas.height = 8;

		var context = canvas.getContext( '2d' );
		context.fillStyle = 'white';
		context.fillRect( 0, 0, 8, 8 );

		texture = new THREE.Texture( canvas );
		texture.needsUpdate = true;

	};

	this.render = function ( scene, camera ) {

		if ( sprites.length === 0 ) return;

		// setup gl

		if ( program === undefined ) {

			init();

		}

		gl.useProgram( program );

		gl.enableVertexAttribArray( attributes.position );
		gl.enableVertexAttribArray( attributes.uv );

		gl.disable( gl.CULL_FACE );
		gl.enable( gl.BLEND );

		gl.bindBuffer( gl.ARRAY_BUFFER, 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, 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

		for ( var i = 0, l = sprites.length; i < l; i ++ ) {

			var sprite = sprites[ i ];

			sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
			sprite.z = - sprite._modelViewMatrix.elements[ 14 ];

		}

		sprites.sort( painterSortStable );

		// render all sprites

		var scale = [];

		for ( var i = 0, l = sprites.length; i < l; i ++ ) {

			var sprite = sprites[ i ];
			var material = sprite.material;

			gl.uniform1f( uniforms.alphaTest, material.alphaTest );
			gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );

			sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );

			scale[ 0 ] = spriteScale.x;
			scale[ 1 ] = spriteScale.y;

			var fogType = 0;

			if ( scene.fog && material.fog ) {

				fogType = sceneFogType;

			}

			if ( oldFogType !== fogType ) {

				gl.uniform1i( uniforms.fogType, fogType );
				oldFogType = fogType;

			}

			if ( material.map !== null ) {

				gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
				gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );

			} else {

				gl.uniform2f( uniforms.uvOffset, 0, 0 );
				gl.uniform2f( uniforms.uvScale, 1, 1 );

			}

			gl.uniform1f( uniforms.opacity, material.opacity );
			gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );

			gl.uniform1f( uniforms.rotation, material.rotation );
			gl.uniform2fv( uniforms.scale, scale );

			renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
			renderer.state.setDepthTest( material.depthTest );
			renderer.state.setDepthWrite( material.depthWrite );

			if ( material.map && material.map.image && material.map.image.width ) {

				renderer.setTexture( material.map, 0 );

			} else {

				renderer.setTexture( texture, 0 );

			}

			gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );

		}

		// restore gl

		gl.enable( gl.CULL_FACE );

		renderer.resetGLState();

	};

	function createProgram () {

		var program = gl.createProgram();

		var vertexShader = gl.createShader( gl.VERTEX_SHADER );
		var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );

		gl.shaderSource( vertexShader, [

			'precision ' + renderer.getPrecision() + ' float;',

			'uniform mat4 modelViewMatrix;',
			'uniform mat4 projectionMatrix;',
			'uniform float rotation;',
			'uniform vec2 scale;',
			'uniform vec2 uvOffset;',
			'uniform vec2 uvScale;',

			'attribute vec2 position;',
			'attribute vec2 uv;',

			'varying vec2 vUV;',

			'void main() {',

				'vUV = uvOffset + uv * uvScale;',

				'vec2 alignedPosition = position * scale;',

				'vec2 rotatedPosition;',
				'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
				'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',

				'vec4 finalPosition;',

				'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
				'finalPosition.xy += rotatedPosition;',
				'finalPosition = projectionMatrix * finalPosition;',

				'gl_Position = finalPosition;',

			'}'

		].join( '\n' ) );

		gl.shaderSource( fragmentShader, [

			'precision ' + renderer.getPrecision() + ' float;',

			'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' ) );

		gl.compileShader( vertexShader );
		gl.compileShader( fragmentShader );

		gl.attachShader( program, vertexShader );
		gl.attachShader( program, fragmentShader );

		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;

		}

	};

};

// File:src/extras/GeometryUtils.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.GeometryUtils = {

	merge: function ( geometry1, geometry2, materialIndexOffset ) {

		THREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );

		var matrix;

		if ( geometry2 instanceof THREE.Mesh ) {

			geometry2.matrixAutoUpdate && geometry2.updateMatrix();

			matrix = geometry2.matrix;
			geometry2 = geometry2.geometry;

		}

		geometry1.merge( geometry2, matrix, materialIndexOffset );

	},

	center: function ( geometry ) {

		THREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
		return geometry.center();

	}

};

// File:src/extras/ImageUtils.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author Daosheng Mu / https://github.com/DaoshengMu/
 */

THREE.ImageUtils = {

	crossOrigin: undefined,

	loadTexture: function ( url, mapping, onLoad, onError ) {

		var loader = new THREE.ImageLoader();
		loader.crossOrigin = this.crossOrigin;

		var texture = new THREE.Texture( undefined, mapping );

		loader.load( url, function ( image ) {

			texture.image = image;
			texture.needsUpdate = true;

			if ( onLoad ) onLoad( texture );

		}, undefined, function ( event ) {

			if ( onError ) onError( event );

		} );

		texture.sourceFile = url;

		return texture;

	},

	loadTextureCube: function ( array, mapping, onLoad, onError ) {

		var images = [];

		var loader = new THREE.ImageLoader();
		loader.crossOrigin = this.crossOrigin;

		var texture = new THREE.CubeTexture( images, mapping );

		// no flipping needed for cube textures

		texture.flipY = false;

		var loaded = 0;

		var loadTexture = function ( i ) {

			loader.load( array[ i ], function ( image ) {

				texture.images[ i ] = image;

				loaded += 1;

				if ( loaded === 6 ) {

					texture.needsUpdate = true;

					if ( onLoad ) onLoad( texture );

				}

			}, undefined, onError );

		}

		for ( var i = 0, il = array.length; i < il; ++ i ) {

			loadTexture( i );

		}

		return texture;

	},

	loadCompressedTexture: function () {

		THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' )

	},

	loadCompressedTextureCube: function () {

		THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' )

	},

	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;

	}

};

// File:src/extras/SceneUtils.js

/**
 * @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 );

	}

};

// File:src/extras/FontUtils.js

/**
 * @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 () {

		try {

			return this.faces[ this.face ][ this.weight ][ this.style ];

		} catch (e) {

			throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing."

		};

	},

	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;

		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;

		return data;

	},

	drawText: function ( text ) {

		// RenderText

		var i,
			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;
							THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
							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( cpx1, cpy1, cpx2, cpy2, 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;
							THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
							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.
				THREE.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' );

				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 ++ ) {

			px = contour[ verts[ p ] ].x
			py = contour[ verts[ p ] ].y

			if ( ( ( px === ax ) && ( py === ay ) ) ||
				 ( ( px === bx ) && ( py === by ) ) ||
				 ( ( px === cx ) && ( py === cy ) ) )	continue;

			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 >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) 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;

// File:src/extras/audio/Audio.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Audio = function ( listener ) {

	THREE.Object3D.call( this );

	this.type = 'Audio';

	this.context = listener.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 = false;

	this.startTime = 0;
	this.isPlaying = false;

};

THREE.Audio.prototype = Object.create( THREE.Object3D.prototype );
THREE.Audio.prototype.constructor = THREE.Audio;

THREE.Audio.prototype.load = function ( file ) {

	var scope = this;

	var request = new XMLHttpRequest();
	request.open( 'GET', file, true );
	request.responseType = 'arraybuffer';
	request.onload = function ( e ) {

		scope.context.decodeAudioData( this.response, function ( buffer ) {

			scope.source.buffer = buffer;

			if( scope.autoplay ) scope.play();

		} );

	};
	request.send();

	return this;

};

THREE.Audio.prototype.play = function () {

	if ( this.isPlaying === true ) {

		THREE.warn( 'THREE.Audio: Audio is already playing.' );
		return;

	}

	var source = this.context.createBufferSource();

	source.buffer = this.source.buffer;
	source.loop = this.source.loop;
	source.onended = this.source.onended;
	source.connect( this.panner );
	source.start( 0, this.startTime );

	this.isPlaying = true;

	this.source = source;

};

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.onEnded = function() {

	this.isPlaying = false;

};

THREE.Audio.prototype.setLoop = function ( value ) {

	this.source.loop = value;

};

THREE.Audio.prototype.setRefDistance = function ( value ) {

	this.panner.refDistance = value;

};

THREE.Audio.prototype.setRolloffFactor = function ( value ) {

	this.panner.rolloffFactor = value;

};

THREE.Audio.prototype.setVolume = function ( value ) {

	this.gain.gain.value = value;

};

THREE.Audio.prototype.updateMatrixWorld = ( function () {

	var position = new THREE.Vector3();

	return function ( force ) {

		THREE.Object3D.prototype.updateMatrixWorld.call( this, force );

		position.setFromMatrixPosition( this.matrixWorld );

		this.panner.setPosition( position.x, position.y, position.z );

	};

} )();

// File:src/extras/audio/AudioListener.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.AudioListener = function () {

	THREE.Object3D.call( this );

	this.type = 'AudioListener';

	this.context = new ( window.AudioContext || window.webkitAudioContext )();

};

THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype );
THREE.AudioListener.prototype.constructor = THREE.AudioListener;

THREE.AudioListener.prototype.updateMatrixWorld = ( function () {

	var position = new THREE.Vector3();
	var quaternion = new THREE.Quaternion();
	var scale = new THREE.Vector3();

	var orientation = new THREE.Vector3();
	var velocity = new THREE.Vector3();

	var positionPrev = new THREE.Vector3();

	return function ( force ) {

		THREE.Object3D.prototype.updateMatrixWorld.call( this, force );

		var listener = this.context.listener;
		var up = this.up;

		this.matrixWorld.decompose( position, quaternion, scale );

		orientation.set( 0, 0, -1 ).applyQuaternion( quaternion );
		velocity.subVectors( position, positionPrev );

		listener.setPosition( position.x, position.y, position.z );
		listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );
		listener.setVelocity( velocity.x, velocity.y, velocity.z );

		positionPrev.copy( position );

	};

} )();

// File:src/extras/core/Curve.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 following classes subclasses THREE.Curve:
 *
 * -- 2d classes --
 * 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 ) {

	THREE.warn( "THREE.Curve: 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;

		} else if ( comparison > 0 ) {

			high = i - 1;

		} 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 );

};





/**************************************************************
 *	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.constructor = constructor;
	constructor.prototype.getPoint = getPointFunc;

	return constructor;

};

// File:src/extras/core/CurvePath.js

/**
 * @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.constructor = THREE.CurvePath;

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 );

		}

		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

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

	};

	if ( v3 ) {

		ret.maxZ = maxZ;
		ret.minZ = minZ;

	}

	return ret;

};

/**************************************************************
 *	Create Geometries Helpers
 **************************************************************/

/// Generate geometry from path points (for Line or Points 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.getTangent( xNorm );
		normal.set( - normal.y, normal.x ).multiplyScalar( oldY );

		p.x = pathPt.x + normal.x;
		p.y = pathPt.y + normal.y;

	}

	return oldPts;

};


// File:src/extras/core/Gyroscope.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Gyroscope = function () {

	THREE.Object3D.call( this );

};

THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );
THREE.Gyroscope.prototype.constructor = THREE.Gyroscope;

THREE.Gyroscope.prototype.updateMatrixWorld = ( function () {

	var translationObject = new THREE.Vector3();
	var quaternionObject = new THREE.Quaternion();
	var scaleObject = new THREE.Vector3();

	var translationWorld = new THREE.Vector3();
	var quaternionWorld = new THREE.Quaternion();
	var scaleWorld = new THREE.Vector3();

	return 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( translationWorld, quaternionWorld, scaleWorld );
				this.matrix.decompose( translationObject, quaternionObject, scaleObject );

				this.matrixWorld.compose( translationWorld, quaternionObject, 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 );

		}

	};
	
}() );

// File:src/extras/core/Path.js

/**
 * @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.Path.prototype.constructor = THREE.Path;

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(1);
	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
//
//	Assumptions (if parameter isCCW==true the opposite holds):
//	- solid shapes are defined clockwise (CW)
//	- holes are defined counterclockwise (CCW)
//
//	If parameter noHoles==true:
//  - all subPaths are regarded as solid shapes
//  - definition order CW/CCW has no relevance
//

THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {

	function extractSubpaths( inActions ) {

		var i, il, item, action, args;

		var subPaths = [], lastPath = new THREE.Path();

		for ( i = 0, il = inActions.length; i < il; i ++ ) {

			item = inActions[ 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);

		return	subPaths;
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

		for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) {

			var tmpPath = inSubpaths[ i ];

			var tmpShape = new THREE.Shape();
			tmpShape.actions = tmpPath.actions;
			tmpShape.curves = tmpPath.curves;

			shapes.push( tmpShape );
		}

		//console.log("shape", shapes);

		return shapes;
	};

	function isPointInsidePolygon( inPt, inPolygon ) {
		var EPSILON = 0.0000000001;

		var polyLen = inPolygon.length;

		// inPt on polygon contour => immediate success    or
		// toggling of inside/outside at every single! intersection point of an edge
		//  with the horizontal line through inPt, left of inPt
		//  not counting lowerY endpoints of edges and whole edges on that line
		var inside = false;
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
			var edgeLowPt  = inPolygon[ p ];
			var edgeHighPt = inPolygon[ q ];

			var edgeDx = edgeHighPt.x - edgeLowPt.x;
			var edgeDy = edgeHighPt.y - edgeLowPt.y;

			if ( Math.abs(edgeDy) > EPSILON ) {			// not parallel
				if ( edgeDy < 0 ) {
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

				if ( inPt.y == edgeLowPt.y ) {
					if ( inPt.x == edgeLowPt.x )		return	true;		// inPt is on contour ?
					// continue;				// no intersection or edgeLowPt => doesn't count !!!
				} else {
					var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
					if ( perpEdge == 0 )				return	true;		// inPt is on contour ?
					if ( perpEdge < 0 ) 				continue;
					inside = ! inside;		// true intersection left of inPt
				}
			} else {		// parallel or colinear
				if ( inPt.y != edgeLowPt.y ) 		continue;			// parallel
				// egde lies on the same horizontal line as inPt
				if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
					 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
				// continue;
			}
		}

		return	inside;
	}


	var subPaths = extractSubpaths( this.actions );
	if ( subPaths.length == 0 ) return [];

	if ( noHoles === true )	return	toShapesNoHoles( subPaths );


	var solid, tmpPath, tmpShape, shapes = [];

	if ( subPaths.length == 1) {

		tmpPath = subPaths[0];
		tmpShape = new THREE.Shape();
		tmpShape.actions = tmpPath.actions;
		tmpShape.curves = tmpPath.curves;
		shapes.push( tmpShape );
		return shapes;

	}

	var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
	holesFirst = isCCW ? ! holesFirst : holesFirst;

	// console.log("Holes first", holesFirst);
	
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;

	newShapes[mainIdx] = undefined;
	newShapeHoles[mainIdx] = [];

	var i, il;

	for ( i = 0, il = subPaths.length; i < il; i ++ ) {

		tmpPath = subPaths[ i ];
		tmpPoints = tmpPath.getPoints();
		solid = THREE.Shape.Utils.isClockWise( tmpPoints );
		solid = isCCW ? ! solid : solid;

		if ( solid ) {

			if ( (! holesFirst ) && ( newShapes[mainIdx] ) )	mainIdx ++;

			newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[mainIdx].s.actions = tmpPath.actions;
			newShapes[mainIdx].s.curves = tmpPath.curves;
			
			if ( holesFirst )	mainIdx ++;
			newShapeHoles[mainIdx] = [];

			//console.log('cw', i);

		} else {

			newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } );

			//console.log('ccw', i);

		}

	}

	// only Holes? -> probably all Shapes with wrong orientation
	if ( ! newShapes[0] )	return	toShapesNoHoles( subPaths );


	if ( newShapes.length > 1 ) {
		var ambigious = false;
		var toChange = [];

		for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
			betterShapeHoles[sIdx] = [];
		}
		for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
			var sho = newShapeHoles[sIdx];
			for (var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
				var ho = sho[hIdx];
				var hole_unassigned = true;
				for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
					if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) {
						if ( sIdx != s2Idx )		toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
						if ( hole_unassigned ) {
							hole_unassigned = false;
							betterShapeHoles[s2Idx].push( ho );
						} else {
							ambigious = true;
						}
					}
				}
				if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); }
			}
		}
		// console.log("ambigious: ", ambigious);
		if ( toChange.length > 0 ) {
			// console.log("to change: ", toChange);
			if (! ambigious)	newShapeHoles = betterShapeHoles;
		}
	}

	var tmpHoles, j, jl;
	for ( i = 0, il = newShapes.length; i < il; i ++ ) {
		tmpShape = newShapes[i].s;
		shapes.push( tmpShape );
		tmpHoles = newShapeHoles[i];
		for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
			tmpShape.holes.push( tmpHoles[j].h );
		}
	}

	//console.log("shape", shapes);

	return shapes;

};

// File:src/extras/core/Shape.js

/**
 * @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 );
THREE.Shape.prototype.constructor = THREE.Shape;

// 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 = {

	triangulateShape: function ( contour, holes ) {

		function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
			// inOtherPt needs to be colinear to the inSegment
			if ( inSegPt1.x != inSegPt2.x ) {
				if ( inSegPt1.x < inSegPt2.x ) {
					return	( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
				} else {
					return	( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
				}
			} else {
				if ( inSegPt1.y < inSegPt2.y ) {
					return	( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
				} else {
					return	( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
				}
			}
		}

		function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
			var EPSILON = 0.0000000001;

			var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x,   seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
			var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x,   seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;

			var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
			var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;

			var limit		= seg1dy * seg2dx - seg1dx * seg2dy;
			var perpSeg1	= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;

			if ( Math.abs(limit) > EPSILON ) {			// not parallel

				var perpSeg2;
				if ( limit > 0 ) {
					if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) 		return [];
					perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
					if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) 		return [];
				} else {
					if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) 		return [];
					perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
					if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) 		return [];
				}

				// i.e. to reduce rounding errors
				// intersection at endpoint of segment#1?
				if ( perpSeg2 == 0 ) {
					if ( ( inExcludeAdjacentSegs ) &&
						 ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )		return [];
					return [ inSeg1Pt1 ];
				}
				if ( perpSeg2 == limit ) {
					if ( ( inExcludeAdjacentSegs ) &&
						 ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )		return [];
					return [ inSeg1Pt2 ];
				}
				// intersection at endpoint of segment#2?
				if ( perpSeg1 == 0 )		return [ inSeg2Pt1 ];
				if ( perpSeg1 == limit )	return [ inSeg2Pt2 ];

				// return real intersection point
				var factorSeg1 = perpSeg2 / limit;
				return	[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
							y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];

			} else {		// parallel or colinear
				if ( ( perpSeg1 != 0 ) ||
					 ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) 			return [];

				// they are collinear or degenerate
				var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) );	// segment1 ist just a point?
				var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) );	// segment2 ist just a point?
				// both segments are points
				if ( seg1Pt && seg2Pt ) {
					if ( (inSeg1Pt1.x != inSeg2Pt1.x) ||
						 (inSeg1Pt1.y != inSeg2Pt1.y) )		return [];   	// they are distinct  points
					return [ inSeg1Pt1 ];                 					// they are the same point
				}
				// segment#1  is a single point
				if ( seg1Pt ) {
					if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )		return [];		// but not in segment#2
					return [ inSeg1Pt1 ];
				}
				// segment#2  is a single point
				if ( seg2Pt ) {
					if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )		return [];		// but not in segment#1
					return [ inSeg2Pt1 ];
				}

				// they are collinear segments, which might overlap
				var seg1min, seg1max, seg1minVal, seg1maxVal;
				var seg2min, seg2max, seg2minVal, seg2maxVal;
				if (seg1dx != 0) {		// the segments are NOT on a vertical line
					if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
						seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
						seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
					} else {
						seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
						seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
					}
					if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
						seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
						seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
					} else {
						seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
						seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
					}
				} else {				// the segments are on a vertical line
					if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
						seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
						seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
					} else {
						seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
						seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
					}
					if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
						seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
						seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
					} else {
						seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
						seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
					}
				}
				if ( seg1minVal <= seg2minVal ) {
					if ( seg1maxVal <  seg2minVal )	return [];
					if ( seg1maxVal == seg2minVal )	{
						if ( inExcludeAdjacentSegs )		return [];
						return [ seg2min ];
					}
					if ( seg1maxVal <= seg2maxVal )	return [ seg2min, seg1max ];
					return	[ seg2min, seg2max ];
				} else {
					if ( seg1minVal >  seg2maxVal )	return [];
					if ( seg1minVal == seg2maxVal )	{
						if ( inExcludeAdjacentSegs )		return [];
						return [ seg1min ];
					}
					if ( seg1maxVal <= seg2maxVal )	return [ seg1min, seg1max ];
					return	[ seg1min, seg2max ];
				}
			}
		}

		function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
			// The order of legs is important

			var EPSILON = 0.0000000001;

			// translation of all points, so that Vertex is at (0,0)
			var legFromPtX	= inLegFromPt.x - inVertex.x,  legFromPtY	= inLegFromPt.y - inVertex.y;
			var legToPtX	= inLegToPt.x	- inVertex.x,  legToPtY		= inLegToPt.y	- inVertex.y;
			var otherPtX	= inOtherPt.x	- inVertex.x,  otherPtY		= inOtherPt.y	- inVertex.y;

			// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
			var from2toAngle	= legFromPtX * legToPtY - legFromPtY * legToPtX;
			var from2otherAngle	= legFromPtX * otherPtY - legFromPtY * otherPtX;

			if ( Math.abs(from2toAngle) > EPSILON ) {			// angle != 180 deg.

				var other2toAngle		= otherPtX * legToPtY - otherPtY * legToPtX;
				// console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );

				if ( from2toAngle > 0 ) {				// main angle < 180 deg.
					return	( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
				} else {								// main angle > 180 deg.
					return	( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
				}
			} else {										// angle == 180 deg.
				// console.log( "from2to: 180 deg., from2other: " + from2otherAngle  );
				return	( from2otherAngle > 0 );
			}
		}


		function removeHoles( contour, holes ) {

			var shape = contour.concat(); // work on this shape
			var hole;

			function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
				// Check if hole point lies within angle around shape point
				var lastShapeIdx = shape.length - 1;

				var prevShapeIdx = inShapeIdx - 1;
				if ( prevShapeIdx < 0 )			prevShapeIdx = lastShapeIdx;

				var nextShapeIdx = inShapeIdx + 1;
				if ( nextShapeIdx > lastShapeIdx )	nextShapeIdx = 0;

				var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] );
				if (! insideAngle ) {
					// console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
					return	false;
				}

				// Check if shape point lies within angle around hole point
				var lastHoleIdx = hole.length - 1;

				var prevHoleIdx = inHoleIdx - 1;
				if ( prevHoleIdx < 0 )			prevHoleIdx = lastHoleIdx;

				var nextHoleIdx = inHoleIdx + 1;
				if ( nextHoleIdx > lastHoleIdx )	nextHoleIdx = 0;

				insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] );
				if (! insideAngle ) {
					// console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
					return	false;
				}

				return	true;
			}

			function intersectsShapeEdge( inShapePt, inHolePt ) {
				// checks for intersections with shape edges
				var sIdx, nextIdx, intersection;
				for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
					nextIdx = sIdx + 1; nextIdx %= shape.length;
					intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true );
					if ( intersection.length > 0 )		return	true;
				}

				return	false;
			}

			var indepHoles = [];

			function intersectsHoleEdge( inShapePt, inHolePt ) {
				// checks for intersections with hole edges
				var ihIdx, chkHole,
					hIdx, nextIdx, intersection;
				for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
					chkHole = holes[indepHoles[ihIdx]];
					for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
						nextIdx = hIdx + 1; nextIdx %= chkHole.length;
						intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true );
						if ( intersection.length > 0 )		return	true;
					}
				}
				return	false;
			}

			var holeIndex, shapeIndex,
				shapePt, holePt,
				holeIdx, cutKey, failedCuts = [],
				tmpShape1, tmpShape2,
				tmpHole1, tmpHole2;

			for ( var h = 0, hl = holes.length; h < hl; h ++ ) {

				indepHoles.push( h );

			}

			var minShapeIndex = 0;
			var counter = indepHoles.length * 2;
			while ( indepHoles.length > 0 ) {
				counter --;
				if ( counter < 0 ) {
					console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" );
					break;
				}

				// search for shape-vertex and hole-vertex,
				// which can be connected without intersections
				for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {

					shapePt = shape[ shapeIndex ];
					holeIndex	= - 1;

					// search for hole which can be reached without intersections
					for ( var h = 0; h < indepHoles.length; h ++ ) {
						holeIdx = indepHoles[h];

						// prevent multiple checks
						cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx;
						if ( failedCuts[cutKey] !== undefined )			continue;

						hole = holes[holeIdx];
						for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
							holePt = hole[ h2 ];
							if (! isCutLineInsideAngles( shapeIndex, h2 ) )		continue;
							if ( intersectsShapeEdge( shapePt, holePt ) )		continue;
							if ( intersectsHoleEdge( shapePt, holePt ) )		continue;

							holeIndex = h2;
							indepHoles.splice(h, 1);

							tmpShape1 = shape.slice( 0, shapeIndex + 1 );
							tmpShape2 = shape.slice( shapeIndex );
							tmpHole1 = hole.slice( holeIndex );
							tmpHole2 = hole.slice( 0, holeIndex + 1 );

							shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );

							minShapeIndex = shapeIndex;

							// Debug only, to show the selected cuts
							// glob_CutLines.push( [ shapePt, holePt ] );

							break;
						}
						if ( holeIndex >= 0 )	break;		// hole-vertex found

						failedCuts[cutKey] = true;			// remember failure
					}
					if ( holeIndex >= 0 )	break;		// hole-vertex found
				}
			}

			return shape; 			/* shape with no holes */
		}


		var i, il, f, face,
			key, index,
			allPointsMap = {};

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

		var allpoints = contour.concat();

		for ( var h = 0, hl = holes.length; h < hl; h ++ ) {

			Array.prototype.push.apply( allpoints, holes[h] );

		}

		//console.log( "allpoints",allpoints, allpoints.length );

		// prepare all points map

		for ( i = 0, il = allpoints.length; i < il; i ++ ) {

			key = allpoints[ i ].x + ":" + allpoints[ i ].y;

			if ( allPointsMap[ key ] !== undefined ) {

				THREE.warn( "THREE.Shape: Duplicate point", key );

			}

			allPointsMap[ key ] = i;

		}

		// remove holes by cutting paths to holes and adding them to the shape
		var shapeWithoutHoles = removeHoles( contour, holes );

		var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape
		//console.log( "triangles",triangles, triangles.length );

		// 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;

				}

			}

		}

		return triangles.concat();

	},

	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 );

	}

};


// File:src/extras/curves/LineCurve.js

/**************************************************************
 *	Line
 **************************************************************/

THREE.LineCurve = function ( v1, v2 ) {

	this.v1 = v1;
	this.v2 = v2;

};

THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );
THREE.LineCurve.prototype.constructor = THREE.LineCurve;

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();

};

// File:src/extras/curves/QuadraticBezierCurve.js

/**************************************************************
 *	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.constructor = THREE.QuadraticBezierCurve;


THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {

	var vector = new THREE.Vector2();

	vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
	vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );

	return vector;

};


THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {

	var vector = new THREE.Vector2();

	vector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
	vector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );

	// returns unit vector

	return vector.normalize();

};

// File:src/extras/curves/CubicBezierCurve.js

/**************************************************************
 *	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.constructor = THREE.CubicBezierCurve;

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;

};

// File:src/extras/curves/SplineCurve.js

/**************************************************************
 *	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.constructor = THREE.SplineCurve;

THREE.SplineCurve.prototype.getPoint = function ( t ) {

	var points = this.points;
	var point = ( points.length - 1 ) * t;

	var intPoint = Math.floor( point );
	var weight = point - intPoint;

	var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ]
	var point1 = points[ intPoint ]
	var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]
	var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]

	var vector = new THREE.Vector2();

	vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
	vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );

	return vector;

};

// File:src/extras/curves/EllipseCurve.js

/**************************************************************
 *	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.constructor = THREE.EllipseCurve;

THREE.EllipseCurve.prototype.getPoint = function ( t ) {

	var deltaAngle = this.aEndAngle - this.aStartAngle;

	if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2;
	if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2;

	var angle;

	if ( this.aClockwise === true ) {

		angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle );

	} else {

		angle = this.aStartAngle + t * deltaAngle;

	}
	
	var vector = new THREE.Vector2();

	vector.x = this.aX + this.xRadius * Math.cos( angle );
	vector.y = this.aY + this.yRadius * Math.sin( angle );

	return vector;

};

// File:src/extras/curves/ArcCurve.js

/**************************************************************
 *	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 );
THREE.ArcCurve.prototype.constructor = THREE.ArcCurve;

// File:src/extras/curves/LineCurve3.js

/**************************************************************
 *	Line3D
 **************************************************************/

THREE.LineCurve3 = THREE.Curve.create(

	function ( v1, v2 ) {

		this.v1 = v1;
		this.v2 = v2;

	},

	function ( t ) {

		var vector = new THREE.Vector3();

		vector.subVectors( this.v2, this.v1 ); // diff
		vector.multiplyScalar( t );
		vector.add( this.v1 );

		return vector;

	}

);

// File:src/extras/curves/QuadraticBezierCurve3.js

/**************************************************************
 *	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 vector = new THREE.Vector3();

		vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
		vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
		vector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );

		return vector;

	}

);

// File:src/extras/curves/CubicBezierCurve3.js

/**************************************************************
 *	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 vector = new THREE.Vector3();

		vector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
		vector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
		vector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );

		return vector;

	}

);

// File:src/extras/curves/SplineCurve3.js

/**************************************************************
 *	Spline 3D curve
 **************************************************************/


THREE.SplineCurve3 = THREE.Curve.create(

	function ( points /* array of Vector3 */) {

		this.points = ( points == undefined ) ? [] : points;

	},

	function ( t ) {

		var points = this.points;
		var point = ( points.length - 1 ) * t;

		var intPoint = Math.floor( point );
		var weight = point - intPoint;

		var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ];
		var point1 = points[ intPoint ];
		var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
		var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];

		var vector = new THREE.Vector3();

		vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
		vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );
		vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );

		return vector;

	}

);

// File:src/extras/curves/ClosedSplineCurve3.js

/**************************************************************
 *	Closed Spline 3D curve
 **************************************************************/


THREE.ClosedSplineCurve3 = THREE.Curve.create(

	function ( points /* array of Vector3 */) {

		this.points = ( points == undefined ) ? [] : points;

	},

	function ( t ) {

		var points = this.points;
		var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1

		var intPoint = Math.floor( point );
		var weight = point - intPoint;

		intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;

		var point0 = points[ ( intPoint - 1 ) % points.length ];
		var point1 = points[ ( intPoint     ) % points.length ];
		var point2 = points[ ( intPoint + 1 ) % points.length ];
		var point3 = points[ ( intPoint + 2 ) % points.length ];

		var vector = new THREE.Vector3();

		vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
		vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );
		vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );

		return vector;

	}

);

// File:src/extras/animation/AnimationHandler.js

/**
 * @author mikael emtinger / http://gomo.se/
 */

THREE.AnimationHandler = {

	LINEAR: 0,
	CATMULLROM: 1,
	CATMULLROM_FORWARD: 2,

	//

	add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); },
	get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); },
	remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); },

	//

	animations: [],

	init: function ( data ) {

		if ( data.initialized === true ) return data;

		// 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().fromArray( quat );

				}

			}

			// 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;

			}

		}

		data.initialized = true;

		return data;

	},

	parse: function ( root ) {

		var parseRecurseHierarchy = function ( root, hierarchy ) {

			hierarchy.push( root );

			for ( var c = 0; c < root.children.length; c ++ )
				parseRecurseHierarchy( root.children[ c ], hierarchy );

		};

		// setup hierarchy

		var hierarchy = [];

		if ( root instanceof THREE.SkinnedMesh ) {

			for ( var b = 0; b < root.skeleton.bones.length; b ++ ) {

				hierarchy.push( root.skeleton.bones[ b ] );

			}

		} else {

			parseRecurseHierarchy( root, hierarchy );

		}

		return hierarchy;

	},

	play: function ( animation ) {

		if ( this.animations.indexOf( animation ) === - 1 ) {

			this.animations.push( animation );

		}

	},

	stop: function ( animation ) {

		var index = this.animations.indexOf( animation );

		if ( index !== - 1 ) {

			this.animations.splice( index, 1 );

		}

	},

	update: function ( deltaTimeMS ) {

		for ( var i = 0; i < this.animations.length; i ++ ) {

			this.animations[ i ].resetBlendWeights( );

		}

		for ( var i = 0; i < this.animations.length; i ++ ) {

			this.animations[ i ].update( deltaTimeMS );

		}

	}

};

// File:src/extras/animation/Animation.js

/**
 * @author mikael emtinger / http://gomo.se/
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Animation = function ( root, data ) {

	this.root = root;
	this.data = THREE.AnimationHandler.init( data );
	this.hierarchy = THREE.AnimationHandler.parse( root );

	this.currentTime = 0;
	this.timeScale = 1;

	this.isPlaying = false;
	this.loop = true;
	this.weight = 0;

	this.interpolationType = THREE.AnimationHandler.LINEAR;

};

THREE.Animation.prototype = {

	constructor: THREE.Animation,

	keyTypes:  [ "pos", "rot", "scl" ],

	play: function ( startTime, weight ) {

		this.currentTime = startTime !== undefined ? startTime : 0;
		this.weight = weight !== undefined ? weight : 1;

		this.isPlaying = true;

		this.reset();

		THREE.AnimationHandler.play( this );

	},

	stop: function() {

		this.isPlaying = false;

		THREE.AnimationHandler.stop( this );

	},

	reset: function () {

		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {

			var object = this.hierarchy[ h ];

			if ( object.animationCache === undefined ) {

				object.animationCache = {
					animations: {},
					blending: {
						positionWeight: 0.0,
						quaternionWeight: 0.0,
						scaleWeight: 0.0
					}
				};
			}

			var name = this.data.name;
			var animations = object.animationCache.animations;
			var animationCache = animations[ name ];

			if ( animationCache === undefined ) {

				animationCache = {
					prevKey: { pos: 0, rot: 0, scl: 0 },
					nextKey: { pos: 0, rot: 0, scl: 0 },
					originalMatrix: object.matrix
				};

				animations[ name ] = animationCache;

			}

			// Get keys to match our current time

			for ( var t = 0; t < 3; t ++ ) {

				var type = this.keyTypes[ t ];

				var prevKey = this.data.hierarchy[ h ].keys[ 0 ];
				var nextKey = this.getNextKeyWith( type, h, 1 );

				while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {

					prevKey = nextKey;
					nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );

				}

				animationCache.prevKey[ type ] = prevKey;
				animationCache.nextKey[ type ] = nextKey;

			}

		}

	},

	resetBlendWeights: function () {

		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {

			var object = this.hierarchy[ h ];
			var animationCache = object.animationCache;

			if ( animationCache !== undefined ) {

				var blending = animationCache.blending;

				blending.positionWeight = 0.0;
				blending.quaternionWeight = 0.0;
				blending.scaleWeight = 0.0;

			}

		}

	},

	update: ( function() {

		var points = [];
		var target = new THREE.Vector3();
		var newVector = new THREE.Vector3();
		var newQuat = new THREE.Quaternion();

		// Catmull-Rom spline

		var 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 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
			v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
			v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );

			return v3;

		};

		var 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;

		};

		return function ( delta ) {

			if ( this.isPlaying === false ) return;

			this.currentTime += delta * this.timeScale;

			if ( this.weight === 0 )
				return;

			//

			var duration = this.data.length;

			if ( this.currentTime > duration || this.currentTime < 0 ) {

				if ( this.loop ) {

					this.currentTime %= duration;

					if ( this.currentTime < 0 )
						this.currentTime += duration;

					this.reset();

				} else {

					this.stop();

				}

			}

			for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {

				var object = this.hierarchy[ h ];
				var animationCache = object.animationCache.animations[this.data.name];
				var blending = object.animationCache.blending;

				// loop through pos/rot/scl

				for ( var t = 0; t < 3; t ++ ) {

					// get keys

					var type    = this.keyTypes[ t ];
					var prevKey = animationCache.prevKey[ type ];
					var nextKey = animationCache.nextKey[ type ];

					if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) ||
						( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) {

						prevKey = this.data.hierarchy[ h ].keys[ 0 ];
						nextKey = this.getNextKeyWith( type, h, 1 );

						while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {

							prevKey = nextKey;
							nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );

						}

						animationCache.prevKey[ type ] = prevKey;
						animationCache.nextKey[ type ] = nextKey;

					}

					var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );

					var prevXYZ = prevKey[ type ];
					var nextXYZ = nextKey[ type ];

					if ( scale < 0 ) scale = 0;
					if ( scale > 1 ) scale = 1;

					// interpolate

					if ( type === "pos" ) {

						if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {

							newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
							newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
							newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;

							// blend
							var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
							object.position.lerp( newVector, proportionalWeight );
							blending.positionWeight += this.weight;

						} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
									this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

							points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
							points[ 1 ] = prevXYZ;
							points[ 2 ] = nextXYZ;
							points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];

							scale = scale * 0.33 + 0.33;

							var currentPoint = interpolateCatmullRom( points, scale );
							var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
							blending.positionWeight += this.weight;

							// blend

							var vector = object.position;

							vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight;
							vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight;
							vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight;

							if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

								var forwardPoint = interpolateCatmullRom( points, scale * 1.01 );

								target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
								target.sub( vector );
								target.y = 0;
								target.normalize();

								var angle = Math.atan2( target.x, target.z );
								object.rotation.set( 0, angle, 0 );

							}

						}

					} else if ( type === "rot" ) {

						THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );

						// Avoid paying the cost of an additional slerp if we don't have to
						if ( blending.quaternionWeight === 0 ) {

							object.quaternion.copy(newQuat);
							blending.quaternionWeight = this.weight;

						} else {

							var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight );
							THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );
							blending.quaternionWeight += this.weight;

						}

					} else if ( type === "scl" ) {

						newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
						newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
						newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;

						var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight );
						object.scale.lerp( newVector, proportionalWeight );
						blending.scaleWeight += this.weight;

					}

				}

			}

			return true;

		};

	} )(),

	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 ];

	},

	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 ];

	}

};

// File:src/extras/animation/KeyFrameAnimation.js

/**
 * @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 ( data ) {

	this.root = data.node;
	this.data = THREE.AnimationHandler.init( data );
	this.hierarchy = THREE.AnimationHandler.parse( this.root );
	this.currentTime = 0;
	this.timeScale = 0.001;
	this.isPlaying = false;
	this.isPaused = true;
	this.loop = 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;

		}

	}

};

THREE.KeyFrameAnimation.prototype = {

	constructor: THREE.KeyFrameAnimation,

	play: function ( startTime ) {

		this.currentTime = startTime !== undefined ? startTime : 0;

		if ( this.isPlaying === false ) {

			this.isPlaying = true;

			// 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 ];

				if ( node.animationCache === undefined ) {

					node.animationCache = {};
					node.animationCache.prevKey = null;
					node.animationCache.nextKey = null;
					node.animationCache.originalMatrix = 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.play( this );

	},

	stop: function () {

		this.isPlaying = false;
		this.isPaused  = false;

		THREE.AnimationHandler.stop( 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;

				original.copy( obj.matrix );
				obj.matrix = original;

				delete node.animationCache;

			}

		}

	},

	update: function ( delta ) {

		if ( this.isPlaying === false ) return;

		this.currentTime += delta * this.timeScale;

		//

		var duration = this.data.length;

		if ( this.loop === true && this.currentTime > duration ) {

			this.currentTime %= duration;

		}

		this.currentTime = Math.min( this.currentTime, duration );

		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {

			var object = this.hierarchy[ h ];
			var node = this.data.hierarchy[ h ];

			var keys = node.keys,
				animationCache = node.animationCache;


			if ( keys.length ) {

				var prevKey = animationCache.prevKey;
				var nextKey = animationCache.nextKey;

				if ( nextKey.time <= this.currentTime ) {

					while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {

						prevKey = nextKey;
						nextKey = keys[ prevKey.index + 1 ];

					}

					animationCache.prevKey = prevKey;
					animationCache.nextKey = nextKey;

				}

				if ( nextKey.time >= this.currentTime ) {

					prevKey.interpolate( nextKey, this.currentTime );

				} else {

					prevKey.interpolate( nextKey, nextKey.time );

				}

				this.data.hierarchy[ h ].node.updateMatrix();
				object.matrixWorldNeedsUpdate = true;

			}

		}

	},

	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 ];

	},

	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 ];

	}

};

// File:src/extras/animation/MorphAnimation.js

/**
 * @author mrdoob / http://mrdoob.com
 * @author willy-vvu / http://willy-vvu.github.io
 */

THREE.MorphAnimation = function ( mesh ) {

	this.mesh = mesh;
	this.frames = mesh.morphTargetInfluences.length;
	this.currentTime = 0;
	this.duration = 1000;
	this.loop = true;
	this.lastFrame = 0;
	this.currentFrame = 0;

	this.isPlaying = false;

};

THREE.MorphAnimation.prototype = {

	constructor: THREE.MorphAnimation,

	play: function () {

		this.isPlaying = true;

	},

	pause: function () {

		this.isPlaying = false;

	},

	update: function ( delta ) {

		if ( this.isPlaying === false ) return;

		this.currentTime += delta;

		if ( this.loop === true && this.currentTime > this.duration ) {

			this.currentTime %= this.duration;

		}

		this.currentTime = Math.min( this.currentTime, this.duration );

		var interpolation = this.duration / this.frames;
		var frame = Math.floor( this.currentTime / interpolation );

		var influences = this.mesh.morphTargetInfluences;

		if ( frame != this.currentFrame ) {

			influences[ this.lastFrame ] = 0;
			influences[ this.currentFrame ] = 1;
			influences[ frame ] = 0;

			this.lastFrame = this.currentFrame;
			this.currentFrame = frame;

		}

		influences[ frame ] = ( this.currentTime % interpolation ) / interpolation;
		influences[ this.lastFrame ] = 1 - influences[ frame ];

	}

};

// File:src/extras/geometries/BoxGeometry.js

/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
 */

THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {

	THREE.Geometry.call( this );

	this.type = 'BoxGeometry';

	this.parameters = {
		width: width,
		height: height,
		depth: depth,
		widthSegments: widthSegments,
		heightSegments: heightSegments,
		depthSegments: depthSegments
	};

	this.widthSegments = widthSegments || 1;
	this.heightSegments = heightSegments || 1;
	this.depthSegments = depthSegments || 1;

	var scope = this;

	var width_half = width / 2;
	var height_half = height / 2;
	var depth_half = depth / 2;

	buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px
	buildPlane( 'z', 'y',   1, - 1, depth, height, - width_half, 1 ); // nx
	buildPlane( 'x', 'z',   1,   1, width, depth, height_half, 2 ); // py
	buildPlane( 'x', 'z',   1, - 1, width, depth, - height_half, 3 ); // ny
	buildPlane( 'x', 'y',   1, - 1, width, height, depth_half, 4 ); // pz
	buildPlane( 'x', 'y', - 1, - 1, width, 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 uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY );
				var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY );
				var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY );
				var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY );

				var face = new THREE.Face3( a + offset, b + offset, d + offset );
				face.normal.copy( normal );
				face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
				face.materialIndex = materialIndex;

				scope.faces.push( face );
				scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );

				face = new THREE.Face3( b + offset, c + offset, d + offset );
				face.normal.copy( normal );
				face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
				face.materialIndex = materialIndex;

				scope.faces.push( face );
				scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );

			}

		}

	}

	this.mergeVertices();

};

THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry;

// File:src/extras/geometries/CircleGeometry.js

/**
 * @author hughes
 */

THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {

	THREE.Geometry.call( this );

	this.type = 'CircleGeometry';

	this.parameters = {
		radius: radius,
		segments: segments,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	radius = radius || 50;
	segments = segments !== undefined ? Math.max( 3, segments ) : 8;

	thetaStart = thetaStart !== undefined ? thetaStart : 0;
	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;

	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 ++ ) {

		this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) );
		this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] );

	}

	this.computeFaceNormals();

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

};

THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry;

// File:src/extras/geometries/CubeGeometry.js

/**
 * @author mrdoob / http://mrdoob.com/
 */


THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {

	THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' );
	return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );

 };

// File:src/extras/geometries/CylinderGeometry.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

	THREE.Geometry.call( this );

	this.type = 'CylinderGeometry';

	this.parameters = {
		radiusTop: radiusTop,
		radiusBottom: radiusBottom,
		height: height,
		radialSegments: radialSegments,
		heightSegments: heightSegments,
		openEnded: openEnded,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	radiusTop = radiusTop !== undefined ? radiusTop : 20;
	radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
	height = height !== undefined ? height : 100;

	radialSegments = radialSegments || 8;
	heightSegments = heightSegments || 1;

	openEnded = openEnded !== undefined ? openEnded : false;
	thetaStart = thetaStart !== undefined ? thetaStart : 0;
	thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI;

	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 <= radialSegments; x ++ ) {

			var u = x / radialSegments;

			var vertex = new THREE.Vector3();
			vertex.x = radius * Math.sin( u * thetaLength + thetaStart );
			vertex.y = - v * height + heightHalf;
			vertex.z = radius * Math.cos( u * thetaLength + thetaStart );

			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 < radialSegments; 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.Face3( v1, v2, v4, [ n1, n2, n4 ] ) );
			this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] );

			this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) );
			this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] );

		}

	}

	// top cap

	if ( openEnded === false && radiusTop > 0 ) {

		this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );

		for ( x = 0; x < radialSegments; 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.x, 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 < radialSegments; x ++ ) {

			var v1 = vertices[ heightSegments ][ x + 1 ];
			var v2 = vertices[ heightSegments ][ 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[ heightSegments ][ x + 1 ].clone();
			var uv2 = uvs[ heightSegments ][ x ].clone();
			var uv3 = new THREE.Vector2( uv2.x, 1 );

			this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
			this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );

		}

	}

	this.computeFaceNormals();

};

THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry;

// File:src/extras/geometries/ExtrudeGeometry.js

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Creates extruded geometry from a path shape.
 *
 * parameters = {
 *
 *  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>, // Depth to extrude the shape
 *
 *  bevelEnabled: <bool>, // turn on bevel
 *  bevelThickness: <float>, // how deep into the original shape bevel goes
 *  bevelSize: <float>, // how far from shape 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 );

	this.type = 'ExtrudeGeometry';

	shapes = shapes instanceof Array ? shapes : [ shapes ];

	this.addShapeList( shapes, options );

	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.constructor = THREE.ExtrudeGeometry;

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 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 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 ) THREE.error( "THREE.ExtrudeGeometry: vec does not exist" );

		return vec.clone().multiplyScalar( size ).add( pt );

	}

	var b, bs, t, z,
		vert, vlen = vertices.length,
		face, flen = faces.length;


	// Find directions for point movement


	function getBevelVec( inPt, inPrev, inNext ) {

		var EPSILON = 0.0000000001;
		
		// computes for inPt the corresponding point inPt' on a new contour
		//   shiftet by 1 unit (length of normalized vector) to the left
		// if we walk along contour clockwise, this new contour is outside the old one
		//
		// inPt' is the intersection of the two lines parallel to the two
		//  adjacent edges of inPt at a distance of 1 unit on the left side.
		
		var v_trans_x, v_trans_y, shrink_by = 1;		// resulting translation vector for inPt

		// good reading for geometry algorithms (here: line-line intersection)
		// http://geomalgorithms.com/a05-_intersect-1.html

		var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y;
		var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y;
		
		var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
		
		// check for colinear edges
		var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
		
		if ( Math.abs( colinear0 ) > EPSILON ) {		// not colinear
			
			// length of vectors for normalizing
	
			var v_prev_len = Math.sqrt( v_prev_lensq );
			var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
			
			// shift adjacent points by unit vectors to the left
	
			var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
			var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
			
			var ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
			var ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
	
			// scaling factor for v_prev to intersection point
	
			var sf = (  ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
						( ptNextShift_y - ptPrevShift_y ) * v_next_x    ) /
					  ( v_prev_x * v_next_y - v_prev_y * v_next_x );
	
			// vector from inPt to intersection point
	
			v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
			v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
	
			// Don't normalize!, otherwise sharp corners become ugly
			//  but prevent crazy spikes
			var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y )
			if ( v_trans_lensq <= 2 ) {
				return	new THREE.Vector2( v_trans_x, v_trans_y );
			} else {
				shrink_by = Math.sqrt( v_trans_lensq / 2 );
			}
			
		} else {		// handle special case of colinear edges

			var direction_eq = false;		// assumes: opposite
			if ( v_prev_x > EPSILON ) {
				if ( v_next_x > EPSILON ) { direction_eq = true; }
			} else {
				if ( v_prev_x < - EPSILON ) {
					if ( v_next_x < - EPSILON ) { direction_eq = true; }
				} else {
					if ( Math.sign(v_prev_y) == Math.sign(v_next_y) ) { direction_eq = true; }
				}
			}

			if ( direction_eq ) {
				// console.log("Warning: lines are a straight sequence");
				v_trans_x = - v_prev_y;
				v_trans_y =  v_prev_x;
				shrink_by = Math.sqrt( v_prev_lensq );
			} else {
				// console.log("Warning: lines are a straight spike");
				v_trans_x = v_prev_x;
				v_trans_y = v_prev_y;
				shrink_by = Math.sqrt( v_prev_lensq / 2 );
			}

		}

		return	new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );

	}


	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)

		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 );

			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 );

				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 );

			}

			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 );

			}

		} else {

			// Bottom faces

			for ( i = 0; i < flen; i ++ ) {

				face = faces[ i ];
				f3( face[ 2 ], face[ 1 ], face[ 0 ] );

			}

			// Top faces

			for ( i = 0; i < flen; i ++ ) {

				face = faces[ i ];
				f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );

			}
		}

	}

	// 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 ) {

		a += shapesOffset;
		b += shapesOffset;
		c += shapesOffset;

		// normal, color, material
		scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) );

		var uvs = uvgen.generateTopUV( scope, 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.Face3( a, b, d, null, null, extrudeMaterial ) );
		scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) );

		var uvs = uvgen.generateSideWallUV( scope, a, b, c, d );

		scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] );
		scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] );

	}

};

THREE.ExtrudeGeometry.WorldUVGenerator = {

	generateTopUV: function ( geometry, indexA, indexB, indexC ) {

		var vertices = geometry.vertices;

		var a = vertices[ indexA ];
		var b = vertices[ indexB ];
		var c = vertices[ indexC ];

		return [
			new THREE.Vector2( a.x, a.y ),
			new THREE.Vector2( b.x, b.y ),
			new THREE.Vector2( c.x, c.y )
		];

	},

	generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) {

		var vertices = geometry.vertices;

		var a = vertices[ indexA ];
		var b = vertices[ indexB ];
		var c = vertices[ indexC ];
		var d = vertices[ indexD ];

		if ( Math.abs( a.y - b.y ) < 0.01 ) {
			return [
				new THREE.Vector2( a.x, 1 - a.z ),
				new THREE.Vector2( b.x, 1 - b.z ),
				new THREE.Vector2( c.x, 1 - c.z ),
				new THREE.Vector2( d.x, 1 - d.z )
			];
		} else {
			return [
				new THREE.Vector2( a.y, 1 - a.z ),
				new THREE.Vector2( b.y, 1 - b.z ),
				new THREE.Vector2( c.y, 1 - c.z ),
				new THREE.Vector2( d.y, 1 - d.z )
			];
		}
	}
};

// File:src/extras/geometries/ShapeGeometry.js

/**
 * @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 );

	this.type = 'ShapeGeometry';

	if ( shapes instanceof Array === false ) shapes = [ shapes ];

	this.addShapeList( shapes, options );

	this.computeFaceNormals();

};

THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry;

/**
 * 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 i, l, hole;

	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;

	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.generateTopUV( this, a, b, c ) );

	}

};

// File:src/extras/geometries/LatheGeometry.js

/**
 * @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 );

	this.type = 'LatheGeometry';

	this.parameters = {
		points: points,
		segments: segments,
		phiStart: phiStart,
		phiLength: phiLength
	};

	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;

			var u0 = i * inverseSegments;
			var v0 = j * inversePointLength;
			var u1 = u0 + inverseSegments;
			var v1 = v0 + inversePointLength;

			this.faces.push( new THREE.Face3( a, b, d ) );

			this.faceVertexUvs[ 0 ].push( [

				new THREE.Vector2( u0, v0 ),
				new THREE.Vector2( u1, v0 ),
				new THREE.Vector2( u0, v1 )

			] );

			this.faces.push( new THREE.Face3( b, c, d ) );

			this.faceVertexUvs[ 0 ].push( [

				new THREE.Vector2( u1, v0 ),
				new THREE.Vector2( u1, v1 ),
				new THREE.Vector2( u0, v1 )

			] );


		}

	}

	this.mergeVertices();
	this.computeFaceNormals();
	this.computeVertexNormals();

};

THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry;

// File:src/extras/geometries/PlaneGeometry.js

/**
 * @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 ) {

	console.info( 'THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.' );

	THREE.Geometry.call( this );

	this.type = 'PlaneGeometry';

	this.parameters = {
		width: width,
		height: height,
		widthSegments: widthSegments,
		heightSegments: heightSegments
	};

	this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );

};

THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry;

// File:src/extras/geometries/PlaneBufferGeometry.js

/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 */

THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) {

	THREE.BufferGeometry.call( this );

	this.type = 'PlaneBufferGeometry';

	this.parameters = {
		width: width,
		height: height,
		widthSegments: widthSegments,
		heightSegments: heightSegments
	};

	var width_half = width / 2;
	var height_half = height / 2;

	var gridX = widthSegments || 1;
	var gridY = heightSegments || 1;

	var gridX1 = gridX + 1;
	var gridY1 = gridY + 1;

	var segment_width = width / gridX;
	var segment_height = height / gridY;

	var vertices = new Float32Array( gridX1 * gridY1 * 3 );
	var normals = new Float32Array( gridX1 * gridY1 * 3 );
	var uvs = new Float32Array( gridX1 * gridY1 * 2 );

	var offset = 0;
	var offset2 = 0;

	for ( var iy = 0; iy < gridY1; iy ++ ) {

		var y = iy * segment_height - height_half;

		for ( var ix = 0; ix < gridX1; ix ++ ) {

			var x = ix * segment_width - width_half;

			vertices[ offset     ] = x;
			vertices[ offset + 1 ] = - y;

			normals[ offset + 2 ] = 1;

			uvs[ offset2     ] = ix / gridX;
			uvs[ offset2 + 1 ] = 1 - ( iy / gridY );

			offset += 3;
			offset2 += 2;

		}

	}

	offset = 0;

	var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 );

	for ( var iy = 0; iy < gridY; iy ++ ) {

		for ( var 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;

			indices[ offset     ] = a;
			indices[ offset + 1 ] = b;
			indices[ offset + 2 ] = d;

			indices[ offset + 3 ] = b;
			indices[ offset + 4 ] = c;
			indices[ offset + 5 ] = d;

			offset += 6;

		}

	}

	this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
	this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
	this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
	this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

};

THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry;

// File:src/extras/geometries/RingGeometry.js

/**
 * @author Kaleb Murphy
 */

THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {

	THREE.Geometry.call( this );

	this.type = 'RingGeometry';

	this.parameters = {
		innerRadius: innerRadius,
		outerRadius: outerRadius,
		thetaSegments: thetaSegments,
		phiSegments: phiSegments,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	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( 1, phiSegments ) : 8;

	var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );

	for ( i = 0; i < phiSegments + 1; i ++ ) { // concentric circles inside ring

		for ( o = 0; o < thetaSegments + 1; 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 / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) );
		}

		radius += radiusStep;

	}

	var n = new THREE.Vector3( 0, 0, 1 );

	for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring

		var thetaSegment = i * (thetaSegments + 1);

		for ( o = 0; o < thetaSegments ; o ++ ) { // number of segments per circle

			var segment = o + thetaSegment;

			var v1 = segment;
			var v2 = segment + thetaSegments + 1;
			var v3 = segment + thetaSegments + 2;

			this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) );
			this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]);

			v1 = segment;
			v2 = segment + thetaSegments + 2;
			v3 = segment + 1;

			this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) );
			this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]);

		}
	}

	this.computeFaceNormals();

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

};

THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.RingGeometry.prototype.constructor = THREE.RingGeometry;


// File:src/extras/geometries/SphereGeometry.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {

	THREE.Geometry.call( this );

	this.type = 'SphereGeometry';

	this.parameters = {
		radius: radius,
		widthSegments: widthSegments,
		heightSegments: heightSegments,
		phiStart: phiStart,
		phiLength: phiLength,
		thetaStart: thetaStart,
		thetaLength: thetaLength 
	};

	radius = radius || 50;

	widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
	heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );

	phiStart = phiStart !== undefined ? phiStart : 0;
	phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;

	thetaStart = thetaStart !== undefined ? thetaStart : 0;
	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 < heightSegments; y ++ ) {

		for ( x = 0; x < 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 ) === radius ) {

				uv1.x = ( uv1.x + uv2.x ) / 2;
				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 ) === radius ) {

				uv3.x = ( uv3.x + uv4.x ) / 2;
				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.Face3( v1, v2, v4, [ n1, n2, n4 ] ) );
				this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] );

				this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) );
				this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] );

			}

		}

	}

	this.computeFaceNormals();

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

};

THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry;

// File:src/extras/geometries/TextGeometry.js

/**
 * @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 );

	this.type = 'TextGeometry';

};

THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype );
THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;

// File:src/extras/geometries/TorusGeometry.js

/**
 * @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 );

	this.type = 'TorusGeometry';

	this.parameters = {
		radius: radius,
		tube: tube,
		radialSegments: radialSegments,
		tubularSegments: tubularSegments,
		arc: arc
	};

	radius = radius || 100;
	tube = tube || 40;
	radialSegments = radialSegments || 8;
	tubularSegments = tubularSegments || 6;
	arc = arc || Math.PI * 2;

	var center = new THREE.Vector3(), uvs = [], normals = [];

	for ( var j = 0; j <= radialSegments; j ++ ) {

		for ( var i = 0; i <= tubularSegments; i ++ ) {

			var u = i / tubularSegments * arc;
			var v = j / radialSegments * Math.PI * 2;

			center.x = radius * Math.cos( u );
			center.y = radius * Math.sin( u );

			var vertex = new THREE.Vector3();
			vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
			vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
			vertex.z = tube * Math.sin( v );

			this.vertices.push( vertex );

			uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) );
			normals.push( vertex.clone().sub( center ).normalize() );

		}

	}

	for ( var j = 1; j <= radialSegments; j ++ ) {

		for ( var i = 1; i <= tubularSegments; i ++ ) {

			var a = ( tubularSegments + 1 ) * j + i - 1;
			var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
			var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
			var d = ( tubularSegments + 1 ) * j + i;

			var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] );
			this.faces.push( face );
			this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] );

			face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] );
			this.faces.push( face );
			this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] );

		}

	}

	this.computeFaceNormals();

};

THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry;

// File:src/extras/geometries/TorusKnotGeometry.js

/**
 * @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 );

	this.type = 'TorusKnotGeometry';

	this.parameters = {
		radius: radius,
		tube: tube,
		radialSegments: radialSegments,
		tubularSegments: tubularSegments,
		p: p,
		q: q,
		heightScale: heightScale
	};

	radius = radius || 100;
	tube = tube || 40;
	radialSegments = radialSegments || 64;
	tubularSegments = tubularSegments || 8;
	p = p || 2;
	q = q || 3;
	heightScale = heightScale || 1;
	
	var grid = new Array( radialSegments );
	var tang = new THREE.Vector3();
	var n = new THREE.Vector3();
	var bitan = new THREE.Vector3();

	for ( var i = 0; i < radialSegments; ++ i ) {

		grid[ i ] = new Array( tubularSegments );
		var u = i / radialSegments * 2 * p * Math.PI;
		var p1 = getPos( u, q, p, radius, heightScale );
		var p2 = getPos( u + 0.01, q, p, radius, heightScale );
		tang.subVectors( p2, p1 );
		n.addVectors( p2, p1 );

		bitan.crossVectors( tang, n );
		n.crossVectors( bitan, tang );
		bitan.normalize();
		n.normalize();

		for ( var j = 0; j < tubularSegments; ++ j ) {

			var v = j / tubularSegments * 2 * Math.PI;
			var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
			var cy = tube * Math.sin( v );

			var pos = new THREE.Vector3();
			pos.x = p1.x + cx * n.x + cy * bitan.x;
			pos.y = p1.y + cx * n.y + cy * bitan.y;
			pos.z = p1.z + cx * n.z + cy * bitan.z;

			grid[ i ][ j ] = this.vertices.push( pos ) - 1;

		}

	}

	for ( var i = 0; i < radialSegments; ++ i ) {

		for ( var j = 0; j < tubularSegments; ++ j ) {

			var ip = ( i + 1 ) % radialSegments;
			var jp = ( j + 1 ) % tubularSegments;

			var a = grid[ i ][ j ];
			var b = grid[ ip ][ j ];
			var c = grid[ ip ][ jp ];
			var d = grid[ i ][ jp ];

			var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments );
			var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments );
			var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments );
			var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments );

			this.faces.push( new THREE.Face3( a, b, d ) );
			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );

			this.faces.push( new THREE.Face3( b, c, d ) );
			this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );

		}
	}

	this.computeFaceNormals();
	this.computeVertexNormals();

	function getPos( u, in_q, in_p, radius, heightScale ) {

		var cu = Math.cos( u );
		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 );
THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry;

// File:src/extras/geometries/TubeGeometry.js

/**
 * @author WestLangley / https://github.com/WestLangley
 * @author zz85 / https://github.com/zz85
 * @author miningold / https://github.com/miningold
 * @author jonobr1 / https://github.com/jonobr1
 *
 * 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, radialSegments, closed, taper ) {

	THREE.Geometry.call( this );

	this.type = 'TubeGeometry';

	this.parameters = {
		path: path,
		segments: segments,
		radius: radius,
		radialSegments: radialSegments,
		closed: closed
	};

	segments = segments || 64;
	radius = radius || 1;
	radialSegments = radialSegments || 8;
	closed = closed || false;
	taper = taper || THREE.TubeGeometry.NoTaper;

	var grid = [];

	var scope = this,

		tangent,
		normal,
		binormal,

		numpoints = segments + 1,

		u, v, r,

		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( path, segments, 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 ++ ) {

		grid[ i ] = [];

		u = i / ( numpoints - 1 );

		pos = path.getPointAt( u );

		tangent = tangents[ i ];
		normal = normals[ i ];
		binormal = binormals[ i ];

		r = radius * taper( u );

		for ( j = 0; j < radialSegments; j ++ ) {

			v = j / radialSegments * 2 * Math.PI;

			cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
			cy = r * 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;

			grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );

		}
	}


	// construct the mesh

	for ( i = 0; i < segments; i ++ ) {

		for ( j = 0; j < radialSegments; j ++ ) {

			ip = ( closed ) ? (i + 1) % segments : i + 1;
			jp = (j + 1) % radialSegments;

			a = grid[ i ][ j ];		// *** NOT NECESSARILY PLANAR ! ***
			b = grid[ ip ][ j ];
			c = grid[ ip ][ jp ];
			d = grid[ i ][ jp ];

			uva = new THREE.Vector2( i / segments, j / radialSegments );
			uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments );
			uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments );
			uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments );

			this.faces.push( new THREE.Face3( a, b, d ) );
			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );

			this.faces.push( new THREE.Face3( b, c, d ) );
			this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );

		}
	}

	this.computeFaceNormals();
	this.computeVertexNormals();

};

THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry;

THREE.TubeGeometry.NoTaper = function ( u ) {

	return 1;

};

THREE.TubeGeometry.SinusoidalTaper = function ( u ) {

	return Math.sin( Math.PI * u );

};

// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) {

	var	normal = 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;


	// 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( THREE.Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors

			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( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 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 ] );

		}

	}
};

// File:src/extras/geometries/PolyhedronGeometry.js

/**
 * @author clockworkgeek / https://github.com/clockworkgeek
 * @author timothypratley / https://github.com/timothypratley
 * @author WestLangley / http://github.com/WestLangley
*/

THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) {

	THREE.Geometry.call( this );

	this.type = 'PolyhedronGeometry';

	this.parameters = {
		vertices: vertices,
		indices: indices,
		radius: radius,
		detail: detail
	};

	radius = radius || 1;
	detail = detail || 0;

	var that = this;

	for ( var i = 0, l = vertices.length; i < l; i += 3 ) {

		prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );

	}

	var p = this.vertices;

	var faces = [];

	for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) {

		var v1 = p[ indices[ i     ] ];
		var v2 = p[ indices[ i + 1 ] ];
		var v3 = p[ indices[ i + 2 ] ];

		faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );

	}

	var centroid = new THREE.Vector3();

	for ( var i = 0, l = faces.length; i < l; i ++ ) {

		subdivide( faces[ 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;

		}

	}


	// Apply radius

	for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {

		this.vertices[ i ].multiplyScalar( radius );

	}


	// Merge vertices

	this.mergeVertices();

	this.computeFaceNormals();

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), 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() ] );
		that.faces.push( face );

		centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 );

		var azi = azimuth( 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 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();

	}


};

THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry;

// File:src/extras/geometries/DodecahedronGeometry.js

/**
 * @author Abe Pazos / https://hamoid.com
 */

THREE.DodecahedronGeometry = function ( radius, detail ) {

	this.parameters = {
		radius: radius,
		detail: detail
	};

	var t = ( 1 + Math.sqrt( 5 ) ) / 2;
	var r = 1 / t;

	var vertices = [

		// (Â±1, Â±1, Â±1)
		-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, Â±1/Ï†, Â±Ï†)
		 0, -r, -t,     0, -r,  t,
		 0,  r, -t,     0,  r,  t,

		// (Â±1/Ï†, Â±Ï†, 0)
		-r, -t,  0,    -r,  t,  0,
		 r, -t,  0,     r,  t,  0,

		// (Â±Ï†, 0, Â±1/Ï†)
		-t,  0, -r,     t,  0, -r,
		-t,  0,  r,     t,  0,  r
	];

	var indices = [
		 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,     19,  4, 17,
		 1, 12, 14,      1, 14,  5,      1,  5,  9
	];

	THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail );

};

THREE.DodecahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry;

// File:src/extras/geometries/IcosahedronGeometry.js

/**
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.IcosahedronGeometry = function ( radius, 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 indices = [
		 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, indices, radius, detail );

	this.type = 'IcosahedronGeometry';

	this.parameters = {
		radius: radius,
		detail: detail
	};
};

THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry;

// File:src/extras/geometries/OctahedronGeometry.js

/**
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.OctahedronGeometry = function ( radius, detail ) {

	this.parameters = {
		radius: radius,
		detail: detail
	};

	var vertices = [
		1, 0, 0,   - 1, 0, 0,    0, 1, 0,    0,- 1, 0,    0, 0, 1,    0, 0,- 1
	];

	var indices = [
		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, indices, radius, detail );

	this.type = 'OctahedronGeometry';

	this.parameters = {
		radius: radius,
		detail: detail
	};
};

THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry;

// File:src/extras/geometries/TetrahedronGeometry.js

/**
 * @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 indices = [
		 2,  1,  0,    0,  3,  2,    1,  3,  0,    2,  3,  1
	];

	THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail );

	this.type = 'TetrahedronGeometry';

	this.parameters = {
		radius: radius,
		detail: detail
	};

};

THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry;

// File:src/extras/geometries/ParametricGeometry.js

/**
 * @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 );
 *
 */

THREE.ParametricGeometry = function ( func, slices, stacks ) {

	THREE.Geometry.call( this );

	this.type = 'ParametricGeometry';

	this.parameters = {
		func: func,
		slices: slices,
		stacks: stacks
	};

	var verts = this.vertices;
	var faces = this.faces;
	var uvs = this.faceVertexUvs[ 0 ];

	var i, j, p;
	var u, v;

	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 + 1;
			d = (i + 1) * sliceCount + j;

			uva = new THREE.Vector2( j / slices, i / stacks );
			uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks );
			uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks );
			uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks );

			faces.push( new THREE.Face3( a, b, d ) );
			uvs.push( [ uva, uvb, uvd ] );

			faces.push( new THREE.Face3( b, c, d ) );
			uvs.push( [ uvb.clone(), uvc, uvd.clone() ] );

		}

	}

	// console.log(this);

	// magic bullet
	// var diff = this.mergeVertices();
	// console.log('removed ', diff, ' vertices by merging');

	this.computeFaceNormals();
	this.computeVertexNormals();

};

THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype );
THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry;

// File:src/extras/helpers/AxisHelper.js

/**
 * @author sroucheray / http://sroucheray.org/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.AxisHelper = function ( size ) {

	size = size || 1;

	var vertices = new Float32Array( [
		0, 0, 0,  size, 0, 0,
		0, 0, 0,  0, size, 0,
		0, 0, 0,  0, 0, size
	] );

	var colors = new Float32Array( [
		1, 0, 0,  1, 0.6, 0,
		0, 1, 0,  0.6, 1, 0,
		0, 0, 1,  0, 0.6, 1
	] );

	var geometry = new THREE.BufferGeometry();
	geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
	geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );

	THREE.Line.call( this, geometry, material, THREE.LinePieces );

};

THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype );
THREE.AxisHelper.prototype.constructor = THREE.AxisHelper;

// File:src/extras/helpers/ArrowHelper.js

/**
 * @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
 *  color - color in hex value
 *  headLength - Number
 *  headWidth - Number
 */

THREE.ArrowHelper = ( function () {

	var lineGeometry = new THREE.Geometry();
	lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );

	var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 );
	coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) );

	return function ( dir, origin, length, color, headLength, headWidth ) {

		// dir is assumed to be normalized

		THREE.Object3D.call( this );

		if ( color === undefined ) color = 0xffff00;
		if ( length === undefined ) length = 1;
		if ( headLength === undefined ) headLength = 0.2 * length;
		if ( headWidth === undefined ) headWidth = 0.2 * headLength;

		this.position.copy( origin );

		this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) );
		this.line.matrixAutoUpdate = false;
		this.add( this.line );

		this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) );
		this.cone.matrixAutoUpdate = false;
		this.add( this.cone );

		this.setDirection( dir );
		this.setLength( length, headLength, headWidth );

	}

}() );

THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype );
THREE.ArrowHelper.prototype.constructor = THREE.ArrowHelper;

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.99999 ) {

			this.quaternion.set( 0, 0, 0, 1 );

		} else if ( dir.y < - 0.99999 ) {

			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, headLength, headWidth ) {

	if ( headLength === undefined ) headLength = 0.2 * length;
	if ( headWidth === undefined ) headWidth = 0.2 * headLength;

	this.line.scale.set( 1, length - headLength, 1 );
	this.line.updateMatrix();

	this.cone.scale.set( headWidth, headLength, headWidth );
	this.cone.position.y = length;
	this.cone.updateMatrix();

};

THREE.ArrowHelper.prototype.setColor = function ( color ) {

	this.line.material.color.set( color );
	this.cone.material.color.set( color );

};

// File:src/extras/helpers/BoxHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.BoxHelper = function ( object ) {

	var geometry = new THREE.BufferGeometry();
	geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 72 ), 3 ) );

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces );

	if ( object !== undefined ) {

		this.update( object );

	}

};

THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype );
THREE.BoxHelper.prototype.constructor = THREE.BoxHelper;

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;

	/*
	  5____4
	1/___0/|
	| 6__|_7
	2/___3/

	0: max.x, max.y, max.z
	1: min.x, max.y, max.z
	2: min.x, min.y, max.z
	3: max.x, min.y, max.z
	4: max.x, max.y, min.z
	5: min.x, max.y, min.z
	6: min.x, min.y, min.z
	7: max.x, min.y, min.z
	*/

	var vertices = this.geometry.attributes.position.array;

	vertices[  0 ] = max.x; vertices[  1 ] = max.y; vertices[  2 ] = max.z;
	vertices[  3 ] = min.x; vertices[  4 ] = max.y; vertices[  5 ] = max.z;

	vertices[  6 ] = min.x; vertices[  7 ] = max.y; vertices[  8 ] = max.z;
	vertices[  9 ] = min.x; vertices[ 10 ] = min.y; vertices[ 11 ] = max.z;

	vertices[ 12 ] = min.x; vertices[ 13 ] = min.y; vertices[ 14 ] = max.z;
	vertices[ 15 ] = max.x; vertices[ 16 ] = min.y; vertices[ 17 ] = max.z;

	vertices[ 18 ] = max.x; vertices[ 19 ] = min.y; vertices[ 20 ] = max.z;
	vertices[ 21 ] = max.x; vertices[ 22 ] = max.y; vertices[ 23 ] = max.z;

	//

	vertices[ 24 ] = max.x; vertices[ 25 ] = max.y; vertices[ 26 ] = min.z;
	vertices[ 27 ] = min.x; vertices[ 28 ] = max.y; vertices[ 29 ] = min.z;

	vertices[ 30 ] = min.x; vertices[ 31 ] = max.y; vertices[ 32 ] = min.z;
	vertices[ 33 ] = min.x; vertices[ 34 ] = min.y; vertices[ 35 ] = min.z;

	vertices[ 36 ] = min.x; vertices[ 37 ] = min.y; vertices[ 38 ] = min.z;
	vertices[ 39 ] = max.x; vertices[ 40 ] = min.y; vertices[ 41 ] = min.z;

	vertices[ 42 ] = max.x; vertices[ 43 ] = min.y; vertices[ 44 ] = min.z;
	vertices[ 45 ] = max.x; vertices[ 46 ] = max.y; vertices[ 47 ] = min.z;

	//

	vertices[ 48 ] = max.x; vertices[ 49 ] = max.y; vertices[ 50 ] = max.z;
	vertices[ 51 ] = max.x; vertices[ 52 ] = max.y; vertices[ 53 ] = min.z;

	vertices[ 54 ] = min.x; vertices[ 55 ] = max.y; vertices[ 56 ] = max.z;
	vertices[ 57 ] = min.x; vertices[ 58 ] = max.y; vertices[ 59 ] = min.z;

	vertices[ 60 ] = min.x; vertices[ 61 ] = min.y; vertices[ 62 ] = max.z;
	vertices[ 63 ] = min.x; vertices[ 64 ] = min.y; vertices[ 65 ] = min.z;

	vertices[ 66 ] = max.x; vertices[ 67 ] = min.y; vertices[ 68 ] = max.z;
	vertices[ 69 ] = max.x; vertices[ 70 ] = min.y; vertices[ 71 ] = min.z;

	this.geometry.attributes.position.needsUpdate = true;

	this.geometry.computeBoundingSphere();

	this.matrix = object.matrixWorld;
	this.matrixAutoUpdate = false;

};

// File:src/extras/helpers/BoundingBoxHelper.js

/**
 * @author WestLangley / http://github.com/WestLangley
 */

// a helper to show the world-axis-aligned bounding box for an object

THREE.BoundingBoxHelper = function ( object, hex ) {

	var color = ( hex !== undefined ) ? hex : 0x888888;

	this.object = object;

	this.box = new THREE.Box3();

	THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) );

};

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 );

};

// File:src/extras/helpers/CameraHelper.js

/**
 * @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 ) {

	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.matrix = camera.matrixWorld;
	this.matrixAutoUpdate = false;

	this.pointMap = pointMap;

	this.update();

};

THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype );
THREE.CameraHelper.prototype.constructor = THREE.CameraHelper;

THREE.CameraHelper.prototype.update = function () {

	var geometry, pointMap;
	
	var vector = new THREE.Vector3();
	var camera = new THREE.Camera();

	var setPoint = function ( point, x, y, z ) {

		vector.set( x, y, z ).unproject( camera );

		var points = pointMap[ point ];

		if ( points !== undefined ) {

			for ( var i = 0, il = points.length; i < il; i ++ ) {

				geometry.vertices[ points[ i ] ].copy( vector );

			}

		}

	};

	return function () {

		geometry = this.geometry;
		pointMap = this.pointMap;

		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 );

		geometry.verticesNeedUpdate = true;

	};

}();

// File:src/extras/helpers/DirectionalLightHelper.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
 */

THREE.DirectionalLightHelper = function ( light, size ) {

	THREE.Object3D.call( this );

	this.light = light;
	this.light.updateMatrixWorld();

	this.matrix = light.matrixWorld;
	this.matrixAutoUpdate = false;

	size = size || 1;

	var geometry = new THREE.Geometry();
	geometry.vertices.push(
		new THREE.Vector3( - size,   size, 0 ),
		new THREE.Vector3(   size,   size, 0 ),
		new THREE.Vector3(   size, - size, 0 ),
		new THREE.Vector3( - size, - size, 0 ),
		new THREE.Vector3( - size,   size, 0 )
	);

	var material = new THREE.LineBasicMaterial( { fog: false } );
	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );

	this.lightPlane = new THREE.Line( geometry, material );
	this.add( this.lightPlane );

	geometry = new THREE.Geometry();
	geometry.vertices.push(
		new THREE.Vector3(),
		new THREE.Vector3()
	);

	material = new THREE.LineBasicMaterial( { fog: false } );
	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );

	this.targetLine = new THREE.Line( geometry, material );
	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 v1 = new THREE.Vector3();
	var v2 = new THREE.Vector3();
	var v3 = new THREE.Vector3();

	return function () {

		v1.setFromMatrixPosition( this.light.matrixWorld );
		v2.setFromMatrixPosition( this.light.target.matrixWorld );
		v3.subVectors( v2, v1 );

		this.lightPlane.lookAt( v3 );
		this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );

		this.targetLine.geometry.vertices[ 1 ].copy( v3 );
		this.targetLine.geometry.verticesNeedUpdate = true;
		this.targetLine.material.color.copy( this.lightPlane.material.color );

	};

}();

// File:src/extras/helpers/EdgesHelper.js

/**
 * @author WestLangley / http://github.com/WestLangley
 * @param object THREE.Mesh whose geometry will be used
 * @param hex line color
 * @param thresholdAngle the minimim angle (in degrees),
 * between the face normals of adjacent faces,
 * that is required to render an edge. A value of 10 means
 * an edge is only rendered if the angle is at least 10 degrees.
 */

THREE.EdgesHelper = function ( object, hex, thresholdAngle ) {

	var color = ( hex !== undefined ) ? hex : 0xffffff;
	thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;

	var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) );

	var edge = [ 0, 0 ], hash = {};
	var sortFunction = function ( a, b ) { return a - b };

	var keys = [ 'a', 'b', 'c' ];
	var geometry = new THREE.BufferGeometry();

	var geometry2;

	if ( object.geometry instanceof THREE.BufferGeometry ) {

		geometry2 = new THREE.Geometry();
		geometry2.fromBufferGeometry( object.geometry );

	} else {

		geometry2 = object.geometry.clone();

	}

	geometry2.mergeVertices();
	geometry2.computeFaceNormals();

	var vertices = geometry2.vertices;
	var faces = geometry2.faces;
	var numEdges = 0;

	for ( var i = 0, l = faces.length; i < l; i ++ ) {

		var face = faces[ i ];

		for ( var j = 0; j < 3; j ++ ) {

			edge[ 0 ] = face[ keys[ j ] ];
			edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];
			edge.sort( sortFunction );

			var key = edge.toString();

			if ( hash[ key ] === undefined ) {

				hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined };
				numEdges ++;

			} else {

				hash[ key ].face2 = i;

			}

		}

	}

	var coords = new Float32Array( numEdges * 2 * 3 );

	var index = 0;

	for ( var key in hash ) {

		var h = hash[ key ];

		if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) {

			var vertex = vertices[ h.vert1 ];
			coords[ index ++ ] = vertex.x;
			coords[ index ++ ] = vertex.y;
			coords[ index ++ ] = vertex.z;

			vertex = vertices[ h.vert2 ];
			coords[ index ++ ] = vertex.x;
			coords[ index ++ ] = vertex.y;
			coords[ index ++ ] = vertex.z;

		}

	}

	geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) );

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces );

	this.matrix = object.matrixWorld;
	this.matrixAutoUpdate = false;

};

THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype );
THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper;

// File:src/extras/helpers/FaceNormalsHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) {

	this.object = object;

	this.size = ( size !== undefined ) ? size : 1;

	var color = ( hex !== undefined ) ? hex : 0xffff00;

	var width = ( linewidth !== undefined ) ? linewidth : 1;

	var geometry = new THREE.Geometry();

	var faces = this.object.geometry.faces;

	for ( var i = 0, l = faces.length; i < l; i ++ ) {

		geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() );

	}

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces );

	this.matrixAutoUpdate = false;

	this.normalMatrix = new THREE.Matrix3();

	this.update();

};

THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype );
THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper;

THREE.FaceNormalsHelper.prototype.update = function () {

	var vertices = this.geometry.vertices;

	var object = this.object;
	var objectVertices = object.geometry.vertices;
	var objectFaces = object.geometry.faces;
	var objectWorldMatrix = object.matrixWorld;

	object.updateMatrixWorld( true );

	this.normalMatrix.getNormalMatrix( objectWorldMatrix );

	for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) {

		var face = objectFaces[ i ];

		vertices[ i2 ].copy( objectVertices[ face.a ] )
			.add( objectVertices[ face.b ] )
			.add( objectVertices[ face.c ] )
			.divideScalar( 3 )
			.applyMatrix4( objectWorldMatrix );

		vertices[ i2 + 1 ].copy( face.normal )
			.applyMatrix3( this.normalMatrix )
			.normalize()
			.multiplyScalar( this.size )
			.add( vertices[ i2 ] );

	}

	this.geometry.verticesNeedUpdate = true;

	return this;

};


// File:src/extras/helpers/GridHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.GridHelper = function ( size, step ) {

	var geometry = new THREE.Geometry();
	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );

	this.color1 = new THREE.Color( 0x444444 );
	this.color2 = new THREE.Color( 0x888888 );

	for ( var i = - size; i <= size; i += step ) {

		geometry.vertices.push(
			new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ),
			new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size )
		);

		var color = i === 0 ? this.color1 : this.color2;

		geometry.colors.push( color, color, color, color );

	}

	THREE.Line.call( this, geometry, material, THREE.LinePieces );

};

THREE.GridHelper.prototype = Object.create( THREE.Line.prototype );
THREE.GridHelper.prototype.constructor = THREE.GridHelper;

THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) {

	this.color1.set( colorCenterLine );
	this.color2.set( colorGrid );

	this.geometry.colorsNeedUpdate = true;

}

// File:src/extras/helpers/HemisphereLightHelper.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.HemisphereLightHelper = function ( light, sphereSize ) {

	THREE.Object3D.call( this );

	this.light = light;
	this.light.updateMatrixWorld();

	this.matrix = light.matrixWorld;
	this.matrixAutoUpdate = false;

	this.colors = [ new THREE.Color(), new THREE.Color() ];

	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 ].color = this.colors[ i < 4 ? 0 : 1 ];

	}

	var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } );

	this.lightSphere = new THREE.Mesh( geometry, material );
	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 vector = 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( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
		this.lightSphere.geometry.colorsNeedUpdate = true;

	}

}();

// File:src/extras/helpers/PointLightHelper.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.PointLightHelper = function ( light, sphereSize ) {

	this.light = light;
	this.light.updateMatrixWorld();

	var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 );
	var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } );
	material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );

	THREE.Mesh.call( this, geometry, material );

	this.matrix = this.light.matrixWorld;
	this.matrixAutoUpdate = false;

	/*
	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.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 );

	/*
	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 );

	}
	*/

};

// File:src/extras/helpers/SkeletonHelper.js

/**
 * @author Sean Griffin / http://twitter.com/sgrif
 * @author Michael Guerrero / http://realitymeltdown.com
 * @author mrdoob / http://mrdoob.com/
 * @author ikerr / http://verold.com
 */

THREE.SkeletonHelper = function ( object ) {

	this.bones = this.getBoneList( object );

	var geometry = new THREE.Geometry();

	for ( var i = 0; i < this.bones.length; i ++ ) {

		var bone = this.bones[ i ];

		if ( bone.parent instanceof THREE.Bone ) {

			geometry.vertices.push( new THREE.Vector3() );
			geometry.vertices.push( new THREE.Vector3() );
			geometry.colors.push( new THREE.Color( 0, 0, 1 ) );
			geometry.colors.push( new THREE.Color( 0, 1, 0 ) );

		}

	}

	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } );

	THREE.Line.call( this, geometry, material, THREE.LinePieces );

	this.root = object;

	this.matrix = object.matrixWorld;
	this.matrixAutoUpdate = false;

	this.update();

};


THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype );
THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper;

THREE.SkeletonHelper.prototype.getBoneList = function( object ) {

	var boneList = [];

	if ( object instanceof THREE.Bone ) {

		boneList.push( object );

	}

	for ( var i = 0; i < object.children.length; i ++ ) {

		boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) );

	}

	return boneList;

};

THREE.SkeletonHelper.prototype.update = function () {

	var geometry = this.geometry;

	var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld );

	var boneMatrix = new THREE.Matrix4();

	var j = 0;

	for ( var i = 0; i < this.bones.length; i ++ ) {

		var bone = this.bones[ i ];

		if ( bone.parent instanceof THREE.Bone ) {

			boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
			geometry.vertices[ j ].setFromMatrixPosition( boneMatrix );

			boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
			geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix );

			j += 2;

		}

	}

	geometry.verticesNeedUpdate = true;

	geometry.computeBoundingSphere();

};

// File:src/extras/helpers/SpotLightHelper.js

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

THREE.SpotLightHelper = function ( light ) {

	THREE.Object3D.call( this );

	this.light = light;
	this.light.updateMatrixWorld();

	this.matrix = light.matrixWorld;
	this.matrixAutoUpdate = false;

	var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true );

	geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) );
	geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );

	var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } );

	this.cone = new THREE.Mesh( geometry, material );
	this.add( this.cone );

	this.update();

};

THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype );
THREE.SpotLightHelper.prototype.constructor = THREE.SpotLightHelper;

THREE.SpotLightHelper.prototype.dispose = function () {
	this.cone.geometry.dispose();
	this.cone.material.dispose();
};

THREE.SpotLightHelper.prototype.update = function () {

	var vector = new THREE.Vector3();
	var vector2 = new THREE.Vector3();

	return function () {

		var coneLength = this.light.distance ? this.light.distance : 10000;
		var coneWidth = coneLength * Math.tan( this.light.angle );

		this.cone.scale.set( coneWidth, coneWidth, coneLength );

		vector.setFromMatrixPosition( this.light.matrixWorld );
		vector2.setFromMatrixPosition( this.light.target.matrixWorld );

		this.cone.lookAt( vector2.sub( vector ) );

		this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );

	};

}();

// File:src/extras/helpers/VertexNormalsHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) {

	this.object = object;

	this.size = ( size !== undefined ) ? size : 1;

	var color = ( hex !== undefined ) ? hex : 0xff0000;

	var width = ( linewidth !== undefined ) ? linewidth : 1;

	var geometry = new THREE.Geometry();

	var faces = object.geometry.faces;

	for ( var i = 0, l = faces.length; i < l; i ++ ) {

		var face = faces[ i ];

		for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {

			geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() );

		}

	}

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces );

	this.matrixAutoUpdate = false;

	this.normalMatrix = new THREE.Matrix3();

	this.update();

};

THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype );
THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper;

THREE.VertexNormalsHelper.prototype.update = ( function ( object ) {

	var v1 = new THREE.Vector3();

	return function( object ) {

		var keys = [ 'a', 'b', 'c', 'd' ];

		this.object.updateMatrixWorld( true );

		this.normalMatrix.getNormalMatrix( this.object.matrixWorld );

		var vertices = this.geometry.vertices;

		var verts = this.object.geometry.vertices;

		var faces = this.object.geometry.faces;

		var worldMatrix = this.object.matrixWorld;

		var idx = 0;

		for ( var i = 0, l = faces.length; i < l; i ++ ) {

			var face = faces[ i ];

			for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {

				var vertexId = face[ keys[ j ] ];
				var vertex = verts[ vertexId ];

				var normal = face.vertexNormals[ j ];

				vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix );

				v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size );

				v1.add( vertices[ idx ] );
				idx = idx + 1;

				vertices[ idx ].copy( v1 );
				idx = idx + 1;

			}

		}

		this.geometry.verticesNeedUpdate = true;

		return this;

	}

}());

// File:src/extras/helpers/VertexTangentsHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) {

	this.object = object;

	this.size = ( size !== undefined ) ? size : 1;

	var color = ( hex !== undefined ) ? hex : 0x0000ff;

	var width = ( linewidth !== undefined ) ? linewidth : 1;

	var geometry = new THREE.Geometry();

	var faces = object.geometry.faces;

	for ( var i = 0, l = faces.length; i < l; i ++ ) {

		var face = faces[ i ];

		for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) {

			geometry.vertices.push( new THREE.Vector3() );
			geometry.vertices.push( new THREE.Vector3() );

		}

	}

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces );

	this.matrixAutoUpdate = false;

	this.update();

};

THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype );
THREE.VertexTangentsHelper.prototype.constructor = THREE.VertexTangentsHelper;

THREE.VertexTangentsHelper.prototype.update = ( function ( object ) {

	var v1 = new THREE.Vector3();

	return function( object ) {

		var keys = [ 'a', 'b', 'c', 'd' ];

		this.object.updateMatrixWorld( true );

		var vertices = this.geometry.vertices;

		var verts = this.object.geometry.vertices;

		var faces = this.object.geometry.faces;

		var worldMatrix = this.object.matrixWorld;

		var idx = 0;

		for ( var i = 0, l = faces.length; i < l; i ++ ) {

			var face = faces[ i ];

			for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) {

				var vertexId = face[ keys[ j ] ];
				var vertex = verts[ vertexId ];

				var tangent = face.vertexTangents[ j ];

				vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix );

				v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size );

				v1.add( vertices[ idx ] );
				idx = idx + 1;

				vertices[ idx ].copy( v1 );
				idx = idx + 1;

			}

		}

		this.geometry.verticesNeedUpdate = true;

		return this;

	}

}());

// File:src/extras/helpers/WireframeHelper.js

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.WireframeHelper = function ( object, hex ) {

	var color = ( hex !== undefined ) ? hex : 0xffffff;

	var edge = [ 0, 0 ], hash = {};
	var sortFunction = function ( a, b ) { return a - b };

	var keys = [ 'a', 'b', 'c' ];
	var geometry = new THREE.BufferGeometry();

	if ( object.geometry instanceof THREE.Geometry ) {

		var vertices = object.geometry.vertices;
		var faces = object.geometry.faces;
		var numEdges = 0;

		// allocate maximal size
		var edges = new Uint32Array( 6 * faces.length );

		for ( var i = 0, l = faces.length; i < l; i ++ ) {

			var face = faces[ i ];

			for ( var j = 0; j < 3; j ++ ) {

				edge[ 0 ] = face[ keys[ j ] ];
				edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];
				edge.sort( sortFunction );

				var key = edge.toString();

				if ( hash[ key ] === undefined ) {

					edges[ 2 * numEdges ] = edge[ 0 ];
					edges[ 2 * numEdges + 1 ] = edge[ 1 ];
					hash[ key ] = true;
					numEdges ++;

				}

			}

		}

		var coords = new Float32Array( numEdges * 2 * 3 );

		for ( var i = 0, l = numEdges; i < l; i ++ ) {

			for ( var j = 0; j < 2; j ++ ) {

				var vertex = vertices[ edges [ 2 * i + j] ];

				var index = 6 * i + 3 * j;
				coords[ index + 0 ] = vertex.x;
				coords[ index + 1 ] = vertex.y;
				coords[ index + 2 ] = vertex.z;

			}

		}

		geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) );

	} else if ( object.geometry instanceof THREE.BufferGeometry ) {

		if ( object.geometry.attributes.index !== undefined ) { // Indexed BufferGeometry

			var vertices = object.geometry.attributes.position.array;
			var indices = object.geometry.attributes.index.array;
			var drawcalls = object.geometry.drawcalls;
			var numEdges = 0;

			if ( drawcalls.length === 0 ) {

				drawcalls = [ { count : indices.length, index : 0, start : 0 } ];

			}

			// allocate maximal size
			var edges = new Uint32Array( 2 * indices.length );

			for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) {

				var start = drawcalls[ o ].start;
				var count = drawcalls[ o ].count;
				var index = drawcalls[ o ].index;

				for ( var i = start, il = start + count; i < il; i += 3 ) {

					for ( var j = 0; j < 3; j ++ ) {

						edge[ 0 ] = index + indices[ i + j ];
						edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ];
						edge.sort( sortFunction );

						var key = edge.toString();

						if ( hash[ key ] === undefined ) {

							edges[ 2 * numEdges ] = edge[ 0 ];
							edges[ 2 * numEdges + 1 ] = edge[ 1 ];
							hash[ key ] = true;
							numEdges ++;

						}

					}

				}

			}

			var coords = new Float32Array( numEdges * 2 * 3 );

			for ( var i = 0, l = numEdges; i < l; i ++ ) {

				for ( var j = 0; j < 2; j ++ ) {

					var index = 6 * i + 3 * j;
					var index2 = 3 * edges[ 2 * i + j];
					coords[ index + 0 ] = vertices[ index2 ];
					coords[ index + 1 ] = vertices[ index2 + 1 ];
					coords[ index + 2 ] = vertices[ index2 + 2 ];

				}

			}

			geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) );

		} else { // non-indexed BufferGeometry

			var vertices = object.geometry.attributes.position.array;
			var numEdges = vertices.length / 3;
			var numTris = numEdges / 3;

			var coords = new Float32Array( numEdges * 2 * 3 );

			for ( var i = 0, l = numTris; i < l; i ++ ) {

				for ( var j = 0; j < 3; j ++ ) {

					var index = 18 * i + 6 * j;

					var index1 = 9 * i + 3 * j;
					coords[ index + 0 ] = vertices[ index1 ];
					coords[ index + 1 ] = vertices[ index1 + 1 ];
					coords[ index + 2 ] = vertices[ index1 + 2 ];

					var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 );
					coords[ index + 3 ] = vertices[ index2 ];
					coords[ index + 4 ] = vertices[ index2 + 1 ];
					coords[ index + 5 ] = vertices[ index2 + 2 ];

				}

			}

			geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) );

		}

	}

	THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces );

	this.matrix = object.matrixWorld;
	this.matrixAutoUpdate = false;

};

THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype );
THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper;

// File:src/extras/objects/ImmediateRenderObject.js

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ImmediateRenderObject = function () {

	THREE.Object3D.call( this );

	this.render = function ( renderCallback ) {};

};

THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype );
THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject;

// File:src/extras/objects/MorphBlendMesh.js

/**
 * @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.constructor = THREE.MorphBlendMesh;

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 ];

			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 {

		THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" );

	}

};

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;

	}

};


/**
 * A nasty IE hack.
 */
(function () {
    var iev = 0;
    var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
    var trident = !!navigator.userAgent.match(/Trident\/7.0/);
    var rv = navigator.userAgent.indexOf("rv:11.0");

    if (ieold) iev = new Number(RegExp.$1);
    if (navigator.appVersion.indexOf("MSIE 10") != -1) iev = 10;
    if (trident && rv != -1) iev = 11;


    if (iev > 0) {
        HTMLElement.prototype.getBoundingClientRect = (function () {
            var oldGetBoundingClientRect = HTMLElement.prototype.getBoundingClientRect;
            return function () {
                try {
                    return oldGetBoundingClientRect.apply(this, arguments);
                } catch (e) {
                    return {
                        left: '',
                        right: '',
                        top: '',
                        bottom: ''
                    };
                }
            };
        })();
    }
})();

return THREE;
})();

/**
 *  Copyright (c) 2014-2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */


/* 

BSD License

For Immutable JS software

Copyright (c) 2014-2015, Facebook, 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 Facebook 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.

*/

var __LiteMolImmutable;
(function (global, factory) {
    __LiteMolImmutable = factory();
}({}, function () {
    'use strict'; var SLICE$0 = Array.prototype.slice;

    function createClass(ctor, superClass) {
        if (superClass) {
            ctor.prototype = Object.create(superClass.prototype);
        }
        ctor.prototype.constructor = ctor;
    }

    function Iterable(value) {
        return isIterable(value) ? value : Seq(value);
    }


    createClass(KeyedIterable, Iterable);
    function KeyedIterable(value) {
        return isKeyed(value) ? value : KeyedSeq(value);
    }


    createClass(IndexedIterable, Iterable);
    function IndexedIterable(value) {
        return isIndexed(value) ? value : IndexedSeq(value);
    }


    createClass(SetIterable, Iterable);
    function SetIterable(value) {
        return isIterable(value) && !isAssociative(value) ? value : SetSeq(value);
    }



    function isIterable(maybeIterable) {
        return !!(maybeIterable && maybeIterable[IS_ITERABLE_SENTINEL]);
    }

    function isKeyed(maybeKeyed) {
        return !!(maybeKeyed && maybeKeyed[IS_KEYED_SENTINEL]);
    }

    function isIndexed(maybeIndexed) {
        return !!(maybeIndexed && maybeIndexed[IS_INDEXED_SENTINEL]);
    }

    function isAssociative(maybeAssociative) {
        return isKeyed(maybeAssociative) || isIndexed(maybeAssociative);
    }

    function isOrdered(maybeOrdered) {
        return !!(maybeOrdered && maybeOrdered[IS_ORDERED_SENTINEL]);
    }

    Iterable.isIterable = isIterable;
    Iterable.isKeyed = isKeyed;
    Iterable.isIndexed = isIndexed;
    Iterable.isAssociative = isAssociative;
    Iterable.isOrdered = isOrdered;

    Iterable.Keyed = KeyedIterable;
    Iterable.Indexed = IndexedIterable;
    Iterable.Set = SetIterable;


    var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
    var IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';
    var IS_INDEXED_SENTINEL = '@@__IMMUTABLE_INDEXED__@@';
    var IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';

    // Used for setting prototype methods that IE8 chokes on.
    var DELETE = 'delete';

    // Constants describing the size of trie nodes.
    var SHIFT = 5; // Resulted in best performance after ______?
    var SIZE = 1 << SHIFT;
    var MASK = SIZE - 1;

    // A consistent shared value representing "not set" which equals nothing other
    // than itself, and nothing that could be provided externally.
    var NOT_SET = {};

    // Boolean references, Rough equivalent of `bool &`.
    var CHANGE_LENGTH = { value: false };
    var DID_ALTER = { value: false };

    function MakeRef(ref) {
        ref.value = false;
        return ref;
    }

    function SetRef(ref) {
        ref && (ref.value = true);
    }

    // A function which returns a value representing an "owner" for transient writes
    // to tries. The return value will only ever equal itself, and will not equal
    // the return of any subsequent call of this function.
    function OwnerID() { }

    // http://jsperf.com/copy-array-inline
    function arrCopy(arr, offset) {
        offset = offset || 0;
        var len = Math.max(0, arr.length - offset);
        var newArr = new Array(len);
        for (var ii = 0; ii < len; ii++) {
            newArr[ii] = arr[ii + offset];
        }
        return newArr;
    }

    function ensureSize(iter) {
        if (iter.size === undefined) {
            iter.size = iter.__iterate(returnTrue);
        }
        return iter.size;
    }

    function wrapIndex(iter, index) {
        // This implements "is array index" which the ECMAString spec defines as:
        //
        //     A String property name P is an array index if and only if
        //     ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
        //     to 2^32−1.
        //
        // http://www.ecma-international.org/ecma-262/6.0/#sec-array-exotic-objects
        if (typeof index !== 'number') {
            var uint32Index = index >>> 0; // N >>> 0 is shorthand for ToUint32
            if ('' + uint32Index !== index || uint32Index === 4294967295) {
                return NaN;
            }
            index = uint32Index;
        }
        return index < 0 ? ensureSize(iter) + index : index;
    }

    function returnTrue() {
        return true;
    }

    function wholeSlice(begin, end, size) {
        return (begin === 0 || (size !== undefined && begin <= -size)) &&
          (end === undefined || (size !== undefined && end >= size));
    }

    function resolveBegin(begin, size) {
        return resolveIndex(begin, size, 0);
    }

    function resolveEnd(end, size) {
        return resolveIndex(end, size, size);
    }

    function resolveIndex(index, size, defaultIndex) {
        return index === undefined ?
            defaultIndex :
          index < 0 ?
            Math.max(0, size + index) :
            size === undefined ?
            index :
              Math.min(size, index);
    }

    /* global Symbol */

    var ITERATE_KEYS = 0;
    var ITERATE_VALUES = 1;
    var ITERATE_ENTRIES = 2;

    var REAL_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
    var FAUX_ITERATOR_SYMBOL = '@@iterator';

    var ITERATOR_SYMBOL = REAL_ITERATOR_SYMBOL || FAUX_ITERATOR_SYMBOL;


    function Iterator(next) {
        this.next = next;
    }

    Iterator.prototype.toString = function () {
        return '[Iterator]';
    };


    Iterator.KEYS = ITERATE_KEYS;
    Iterator.VALUES = ITERATE_VALUES;
    Iterator.ENTRIES = ITERATE_ENTRIES;

    Iterator.prototype.inspect =
    Iterator.prototype.toSource = function () { return this.toString(); }
    Iterator.prototype[ITERATOR_SYMBOL] = function () {
        return this;
    };


    function iteratorValue(type, k, v, iteratorResult) {
        var value = type === 0 ? k : type === 1 ? v : [k, v];
        iteratorResult ? (iteratorResult.value = value) : (iteratorResult = {
            value: value, done: false
        });
        return iteratorResult;
    }

    function iteratorDone() {
        return { value: undefined, done: true };
    }

    function hasIterator(maybeIterable) {
        return !!getIteratorFn(maybeIterable);
    }

    function isIterator(maybeIterator) {
        return maybeIterator && typeof maybeIterator.next === 'function';
    }

    function getIterator(iterable) {
        var iteratorFn = getIteratorFn(iterable);
        return iteratorFn && iteratorFn.call(iterable);
    }

    function getIteratorFn(iterable) {
        var iteratorFn = iterable && (
          (REAL_ITERATOR_SYMBOL && iterable[REAL_ITERATOR_SYMBOL]) ||
          iterable[FAUX_ITERATOR_SYMBOL]
        );
        if (typeof iteratorFn === 'function') {
            return iteratorFn;
        }
    }

    function isArrayLike(value) {
        return value && typeof value.length === 'number';
    }

    createClass(Seq, Iterable);
    function Seq(value) {
        return value === null || value === undefined ? emptySequence() :
          isIterable(value) ? value.toSeq() : seqFromValue(value);
    }

    Seq.of = function (/*...values*/) {
        return Seq(arguments);
    };

    Seq.prototype.toSeq = function () {
        return this;
    };

    Seq.prototype.toString = function () {
        return this.__toString('Seq {', '}');
    };

    Seq.prototype.cacheResult = function () {
        if (!this._cache && this.__iterateUncached) {
            this._cache = this.entrySeq().toArray();
            this.size = this._cache.length;
        }
        return this;
    };

    // abstract __iterateUncached(fn, reverse)

    Seq.prototype.__iterate = function (fn, reverse) {
        return seqIterate(this, fn, reverse, true);
    };

    // abstract __iteratorUncached(type, reverse)

    Seq.prototype.__iterator = function (type, reverse) {
        return seqIterator(this, type, reverse, true);
    };



    createClass(KeyedSeq, Seq);
    function KeyedSeq(value) {
        return value === null || value === undefined ?
          emptySequence().toKeyedSeq() :
          isIterable(value) ?
            (isKeyed(value) ? value.toSeq() : value.fromEntrySeq()) :
            keyedSeqFromValue(value);
    }

    KeyedSeq.prototype.toKeyedSeq = function () {
        return this;
    };



    createClass(IndexedSeq, Seq);
    function IndexedSeq(value) {
        return value === null || value === undefined ? emptySequence() :
          !isIterable(value) ? indexedSeqFromValue(value) :
          isKeyed(value) ? value.entrySeq() : value.toIndexedSeq();
    }

    IndexedSeq.of = function (/*...values*/) {
        return IndexedSeq(arguments);
    };

    IndexedSeq.prototype.toIndexedSeq = function () {
        return this;
    };

    IndexedSeq.prototype.toString = function () {
        return this.__toString('Seq [', ']');
    };

    IndexedSeq.prototype.__iterate = function (fn, reverse) {
        return seqIterate(this, fn, reverse, false);
    };

    IndexedSeq.prototype.__iterator = function (type, reverse) {
        return seqIterator(this, type, reverse, false);
    };



    createClass(SetSeq, Seq);
    function SetSeq(value) {
        return (
          value === null || value === undefined ? emptySequence() :
          !isIterable(value) ? indexedSeqFromValue(value) :
          isKeyed(value) ? value.entrySeq() : value
        ).toSetSeq();
    }

    SetSeq.of = function (/*...values*/) {
        return SetSeq(arguments);
    };

    SetSeq.prototype.toSetSeq = function () {
        return this;
    };



    Seq.isSeq = isSeq;
    Seq.Keyed = KeyedSeq;
    Seq.Set = SetSeq;
    Seq.Indexed = IndexedSeq;

    var IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@';

    Seq.prototype[IS_SEQ_SENTINEL] = true;



    createClass(ArraySeq, IndexedSeq);
    function ArraySeq(array) {
        this._array = array;
        this.size = array.length;
    }

    ArraySeq.prototype.get = function (index, notSetValue) {
        return this.has(index) ? this._array[wrapIndex(this, index)] : notSetValue;
    };

    ArraySeq.prototype.__iterate = function (fn, reverse) {
        var array = this._array;
        var maxIndex = array.length - 1;
        for (var ii = 0; ii <= maxIndex; ii++) {
            if (fn(array[reverse ? maxIndex - ii : ii], ii, this) === false) {
                return ii + 1;
            }
        }
        return ii;
    };

    ArraySeq.prototype.__iterator = function (type, reverse) {
        var array = this._array;
        var maxIndex = array.length - 1;
        var ii = 0;
        return new Iterator(function () {
            return ii > maxIndex ?
             iteratorDone() :
             iteratorValue(type, ii, array[reverse ? maxIndex - ii++ : ii++])
        }
        );
    };



    createClass(ObjectSeq, KeyedSeq);
    function ObjectSeq(object) {
        var keys = Object.keys(object);
        this._object = object;
        this._keys = keys;
        this.size = keys.length;
    }

    ObjectSeq.prototype.get = function (key, notSetValue) {
        if (notSetValue !== undefined && !this.has(key)) {
            return notSetValue;
        }
        return this._object[key];
    };

    ObjectSeq.prototype.has = function (key) {
        return this._object.hasOwnProperty(key);
    };

    ObjectSeq.prototype.__iterate = function (fn, reverse) {
        var object = this._object;
        var keys = this._keys;
        var maxIndex = keys.length - 1;
        for (var ii = 0; ii <= maxIndex; ii++) {
            var key = keys[reverse ? maxIndex - ii : ii];
            if (fn(object[key], key, this) === false) {
                return ii + 1;
            }
        }
        return ii;
    };

    ObjectSeq.prototype.__iterator = function (type, reverse) {
        var object = this._object;
        var keys = this._keys;
        var maxIndex = keys.length - 1;
        var ii = 0;
        return new Iterator(function () {
            var key = keys[reverse ? maxIndex - ii : ii];
            return ii++ > maxIndex ?
              iteratorDone() :
              iteratorValue(type, key, object[key]);
        });
    };

    ObjectSeq.prototype[IS_ORDERED_SENTINEL] = true;


    createClass(IterableSeq, IndexedSeq);
    function IterableSeq(iterable) {
        this._iterable = iterable;
        this.size = iterable.length || iterable.size;
    }

    IterableSeq.prototype.__iterateUncached = function (fn, reverse) {
        if (reverse) {
            return this.cacheResult().__iterate(fn, reverse);
        }
        var iterable = this._iterable;
        var iterator = getIterator(iterable);
        var iterations = 0;
        if (isIterator(iterator)) {
            var step;
            while (!(step = iterator.next()).done) {
                if (fn(step.value, iterations++, this) === false) {
                    break;
                }
            }
        }
        return iterations;
    };

    IterableSeq.prototype.__iteratorUncached = function (type, reverse) {
        if (reverse) {
            return this.cacheResult().__iterator(type, reverse);
        }
        var iterable = this._iterable;
        var iterator = getIterator(iterable);
        if (!isIterator(iterator)) {
            return new Iterator(iteratorDone);
        }
        var iterations = 0;
        return new Iterator(function () {
            var step = iterator.next();
            return step.done ? step : iteratorValue(type, iterations++, step.value);
        });
    };



    createClass(IteratorSeq, IndexedSeq);
    function IteratorSeq(iterator) {
        this._iterator = iterator;
        this._iteratorCache = [];
    }

    IteratorSeq.prototype.__iterateUncached = function (fn, reverse) {
        if (reverse) {
            return this.cacheResult().__iterate(fn, reverse);
        }
        var iterator = this._iterator;
        var cache = this._iteratorCache;
        var iterations = 0;
        while (iterations < cache.length) {
            if (fn(cache[iterations], iterations++, this) === false) {
                return iterations;
            }
        }
        var step;
        while (!(step = iterator.next()).done) {
            var val = step.value;
            cache[iterations] = val;
            if (fn(val, iterations++, this) === false) {
                break;
            }
        }
        return iterations;
    };

    IteratorSeq.prototype.__iteratorUncached = function (type, reverse) {
        if (reverse) {
            return this.cacheResult().__iterator(type, reverse);
        }
        var iterator = this._iterator;
        var cache = this._iteratorCache;
        var iterations = 0;
        return new Iterator(function () {
            if (iterations >= cache.length) {
                var step = iterator.next();
                if (step.done) {
                    return step;
                }
                cache[iterations] = step.value;
            }
            return iteratorValue(type, iterations, cache[iterations++]);
        });
    };




    // # pragma Helper functions

    function isSeq(maybeSeq) {
        return !!(maybeSeq && maybeSeq[IS_SEQ_SENTINEL]);
    }

    var EMPTY_SEQ;

    function emptySequence() {
        return EMPTY_SEQ || (EMPTY_SEQ = new ArraySeq([]));
    }

    function keyedSeqFromValue(value) {
        var seq =
          Array.isArray(value) ? new ArraySeq(value).fromEntrySeq() :
          isIterator(value) ? new IteratorSeq(value).fromEntrySeq() :
          hasIterator(value) ? new IterableSeq(value).fromEntrySeq() :
          typeof value === 'object' ? new ObjectSeq(value) :
          undefined;
        if (!seq) {
            throw new TypeError(
              'Expected Array or iterable object of [k, v] entries, ' +
              'or keyed object: ' + value
            );
        }
        return seq;
    }

    function indexedSeqFromValue(value) {
        var seq = maybeIndexedSeqFromValue(value);
        if (!seq) {
            throw new TypeError(
              'Expected Array or iterable object of values: ' + value
            );
        }
        return seq;
    }

    function seqFromValue(value) {
        var seq = maybeIndexedSeqFromValue(value) ||
          (typeof value === 'object' && new ObjectSeq(value));
        if (!seq) {
            throw new TypeError(
              'Expected Array or iterable object of values, or keyed object: ' + value
            );
        }
        return seq;
    }

    function maybeIndexedSeqFromValue(value) {
        return (
          isArrayLike(value) ? new ArraySeq(value) :
          isIterator(value) ? new IteratorSeq(value) :
          hasIterator(value) ? new IterableSeq(value) :
          undefined
        );
    }

    function seqIterate(seq, fn, reverse, useKeys) {
        var cache = seq._cache;
        if (cache) {
            var maxIndex = cache.length - 1;
            for (var ii = 0; ii <= maxIndex; ii++) {
                var entry = cache[reverse ? maxIndex - ii : ii];
                if (fn(entry[1], useKeys ? entry[0] : ii, seq) === false) {
                    return ii + 1;
                }
            }
            return ii;
        }
        return seq.__iterateUncached(fn, reverse);
    }

    function seqIterator(seq, type, reverse, useKeys) {
        var cache = seq._cache;
        if (cache) {
            var maxIndex = cache.length - 1;
            var ii = 0;
            return new Iterator(function () {
                var entry = cache[reverse ? maxIndex - ii : ii];
                return ii++ > maxIndex ?
                  iteratorDone() :
                  iteratorValue(type, useKeys ? entry[0] : ii - 1, entry[1]);
            });
        }
        return seq.__iteratorUncached(type, reverse);
    }

    function fromJS(json, converter) {
        return converter ?
          fromJSWith(converter, json, '', { '': json }) :
          fromJSDefault(json);
    }

    function fromJSWith(converter, json, key, parentJSON) {
        if (Array.isArray(json)) {
            return converter.call(parentJSON, key, IndexedSeq(json).map(function (v, k) { return fromJSWith(converter, v, k, json) }));
        }
        if (isPlainObj(json)) {
            return converter.call(parentJSON, key, KeyedSeq(json).map(function (v, k) { return fromJSWith(converter, v, k, json) }));
        }
        return json;
    }

    function fromJSDefault(json) {
        if (Array.isArray(json)) {
            return IndexedSeq(json).map(fromJSDefault).toList();
        }
        if (isPlainObj(json)) {
            return KeyedSeq(json).map(fromJSDefault).toMap();
        }
        return json;
    }

    function isPlainObj(value) {
        return value && (value.constructor === Object || value.constructor === undefined);
    }

    /**
     * An extension of the "same-value" algorithm as [described for use by ES6 Map
     * and Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality)
     *
     * NaN is considered the same as NaN, however -0 and 0 are considered the same
     * value, which is different from the algorithm described by
     * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
     *
     * This is extended further to allow Objects to describe the values they
     * represent, by way of `valueOf` or `equals` (and `hashCode`).
     *
     * Note: because of this extension, the key equality of Immutable.Map and the
     * value equality of Immutable.Set will differ from ES6 Map and Set.
     *
     * ### Defining custom values
     *
     * The easiest way to describe the value an object represents is by implementing
     * `valueOf`. For example, `Date` represents a value by returning a unix
     * timestamp for `valueOf`:
     *
     *     var date1 = new Date(1234567890000); // Fri Feb 13 2009 ...
     *     var date2 = new Date(1234567890000);
     *     date1.valueOf(); // 1234567890000
     *     assert( date1 !== date2 );
     *     assert( Immutable.is( date1, date2 ) );
     *
     * Note: overriding `valueOf` may have other implications if you use this object
     * where JavaScript expects a primitive, such as implicit string coercion.
     *
     * For more complex types, especially collections, implementing `valueOf` may
     * not be performant. An alternative is to implement `equals` and `hashCode`.
     *
     * `equals` takes another object, presumably of similar type, and returns true
     * if the it is equal. Equality is symmetrical, so the same result should be
     * returned if this and the argument are flipped.
     *
     *     assert( a.equals(b) === b.equals(a) );
     *
     * `hashCode` returns a 32bit integer number representing the object which will
     * be used to determine how to store the value object in a Map or Set. You must
     * provide both or neither methods, one must not exist without the other.
     *
     * Also, an important relationship between these methods must be upheld: if two
     * values are equal, they *must* return the same hashCode. If the values are not
     * equal, they might have the same hashCode; this is called a hash collision,
     * and while undesirable for performance reasons, it is acceptable.
     *
     *     if (a.equals(b)) {
     *       assert( a.hashCode() === b.hashCode() );
     *     }
     *
     * All Immutable collections implement `equals` and `hashCode`.
     *
     */
    function is(valueA, valueB) {
        if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) {
            return true;
        }
        if (!valueA || !valueB) {
            return false;
        }
        if (typeof valueA.valueOf === 'function' &&
            typeof valueB.valueOf === 'function') {
            valueA = valueA.valueOf();
            valueB = valueB.valueOf();
            if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) {
                return true;
            }
            if (!valueA || !valueB) {
                return false;
            }
        }
        if (typeof valueA.equals === 'function' &&
            typeof valueB.equals === 'function' &&
            valueA.equals(valueB)) {
            return true;
        }
        return false;
    }

    function deepEqual(a, b) {
        if (a === b) {
            return true;
        }

        if (
          !isIterable(b) ||
          a.size !== undefined && b.size !== undefined && a.size !== b.size ||
          a.__hash !== undefined && b.__hash !== undefined && a.__hash !== b.__hash ||
          isKeyed(a) !== isKeyed(b) ||
          isIndexed(a) !== isIndexed(b) ||
          isOrdered(a) !== isOrdered(b)
        ) {
            return false;
        }

        if (a.size === 0 && b.size === 0) {
            return true;
        }

        var notAssociative = !isAssociative(a);

        if (isOrdered(a)) {
            var entries = a.entries();
            return b.every(function (v, k) {
                var entry = entries.next().value;
                return entry && is(entry[1], v) && (notAssociative || is(entry[0], k));
            }) && entries.next().done;
        }

        var flipped = false;

        if (a.size === undefined) {
            if (b.size === undefined) {
                if (typeof a.cacheResult === 'function') {
                    a.cacheResult();
                }
            } else {
                flipped = true;
                var _ = a;
                a = b;
                b = _;
            }
        }

        var allEqual = true;
        var bSize = b.__iterate(function (v, k) {
            if (notAssociative ? !a.has(v) :
                flipped ? !is(v, a.get(k, NOT_SET)) : !is(a.get(k, NOT_SET), v)) {
                allEqual = false;
                return false;
            }
        });

        return allEqual && a.size === bSize;
    }

    createClass(Repeat, IndexedSeq);

    function Repeat(value, times) {
        if (!(this instanceof Repeat)) {
            return new Repeat(value, times);
        }
        this._value = value;
        this.size = times === undefined ? Infinity : Math.max(0, times);
        if (this.size === 0) {
            if (EMPTY_REPEAT) {
                return EMPTY_REPEAT;
            }
            EMPTY_REPEAT = this;
        }
    }

    Repeat.prototype.toString = function () {
        if (this.size === 0) {
            return 'Repeat []';
        }
        return 'Repeat [ ' + this._value + ' ' + this.size + ' times ]';
    };

    Repeat.prototype.get = function (index, notSetValue) {
        return this.has(index) ? this._value : notSetValue;
    };

    Repeat.prototype.includes = function (searchValue) {
        return is(this._value, searchValue);
    };

    Repeat.prototype.slice = function (begin, end) {
        var size = this.size;
        return wholeSlice(begin, end, size) ? this :
          new Repeat(this._value, resolveEnd(end, size) - resolveBegin(begin, size));
    };

    Repeat.prototype.reverse = function () {
        return this;
    };

    Repeat.prototype.indexOf = function (searchValue) {
        if (is(this._value, searchValue)) {
            return 0;
        }
        return -1;
    };

    Repeat.prototype.lastIndexOf = function (searchValue) {
        if (is(this._value, searchValue)) {
            return this.size;
        }
        return -1;
    };

    Repeat.prototype.__iterate = function (fn, reverse) {
        for (var ii = 0; ii < this.size; ii++) {
            if (fn(this._value, ii, this) === false) {
                return ii + 1;
            }
        }
        return ii;
    };

    Repeat.prototype.__iterator = function (type, reverse) {
        var this$0 = this;
        var ii = 0;
        return new Iterator(function ()
        { return ii < this$0.size ? iteratorValue(type, ii++, this$0._value) : iteratorDone() }
        );
    };

    Repeat.prototype.equals = function (other) {
        return other instanceof Repeat ?
          is(this._value, other._value) :
          deepEqual(other);
    };


    var EMPTY_REPEAT;

    function invariant(condition, error) {
        if (!condition) throw new Error(error);
    }

    createClass(Range, IndexedSeq);

    function Range(start, end, step) {
        if (!(this instanceof Range)) {
            return new Range(start, end, step);
        }
        invariant(step !== 0, 'Cannot step a Range by 0');
        start = start || 0;
        if (end === undefined) {
            end = Infinity;
        }
        step = step === undefined ? 1 : Math.abs(step);
        if (end < start) {
            step = -step;
        }
        this._start = start;
        this._end = end;
        this._step = step;
        this.size = Math.max(0, Math.ceil((end - start) / step - 1) + 1);
        if (this.size === 0) {
            if (EMPTY_RANGE) {
                return EMPTY_RANGE;
            }
            EMPTY_RANGE = this;
        }
    }

    Range.prototype.toString = function () {
        if (this.size === 0) {
            return 'Range []';
        }
        return 'Range [ ' +
          this._start + '...' + this._end +
          (this._step !== 1 ? ' by ' + this._step : '') +
        ' ]';
    };

    Range.prototype.get = function (index, notSetValue) {
        return this.has(index) ?
          this._start + wrapIndex(this, index) * this._step :
          notSetValue;
    };

    Range.prototype.includes = function (searchValue) {
        var possibleIndex = (searchValue - this._start) / this._step;
        return possibleIndex >= 0 &&
          possibleIndex < this.size &&
          possibleIndex === Math.floor(possibleIndex);
    };

    Range.prototype.slice = function (begin, end) {
        if (wholeSlice(begin, end, this.size)) {
            return this;
        }
        begin = resolveBegin(begin, this.size);
        end = resolveEnd(end, this.size);
        if (end <= begin) {
            return new Range(0, 0);
        }
        return new Range(this.get(begin, this._end), this.get(end, this._end), this._step);
    };

    Range.prototype.indexOf = function (searchValue) {
        var offsetValue = searchValue - this._start;
        if (offsetValue % this._step === 0) {
            var index = offsetValue / this._step;
            if (index >= 0 && index < this.size) {
                return index
            }
        }
        return -1;
    };

    Range.prototype.lastIndexOf = function (searchValue) {
        return this.indexOf(searchValue);
    };

    Range.prototype.__iterate = function (fn, reverse) {
        var maxIndex = this.size - 1;
        var step = this._step;
        var value = reverse ? this._start + maxIndex * step : this._start;
        for (var ii = 0; ii <= maxIndex; ii++) {
            if (fn(value, ii, this) === false) {
                return ii + 1;
            }
            value += reverse ? -step : step;
        }
        return ii;
    };

    Range.prototype.__iterator = function (type, reverse) {
        var maxIndex = this.size - 1;
        var step = this._step;
        var value = reverse ? this._start + maxIndex * step : this._start;
        var ii = 0;
        return new Iterator(function () {
            var v = value;
            value += reverse ? -step : step;
            return ii > maxIndex ? iteratorDone() : iteratorValue(type, ii++, v);
        });
    };

    Range.prototype.equals = function (other) {
        return other instanceof Range ?
          this._start === other._start &&
          this._end === other._end &&
          this._step === other._step :
          deepEqual(this, other);
    };


    var EMPTY_RANGE;

    createClass(Collection, Iterable);
    function Collection() {
        throw TypeError('Abstract');
    }


    createClass(KeyedCollection, Collection); function KeyedCollection() { }

    createClass(IndexedCollection, Collection); function IndexedCollection() { }

    createClass(SetCollection, Collection); function SetCollection() { }


    Collection.Keyed = KeyedCollection;
    Collection.Indexed = IndexedCollection;
    Collection.Set = SetCollection;

    var imul =
      typeof Math.imul === 'function' && Math.imul(0xffffffff, 2) === -2 ?
      Math.imul :
      function imul(a, b) {
          a = a | 0; // int
          b = b | 0; // int
          var c = a & 0xffff;
          var d = b & 0xffff;
          // Shift by 0 fixes the sign on the high part.
          return (c * d) + ((((a >>> 16) * d + c * (b >>> 16)) << 16) >>> 0) | 0; // int
      };

    // v8 has an optimization for storing 31-bit signed numbers.
    // Values which have either 00 or 11 as the high order bits qualify.
    // This function drops the highest order bit in a signed number, maintaining
    // the sign bit.
    function smi(i32) {
        return ((i32 >>> 1) & 0x40000000) | (i32 & 0xBFFFFFFF);
    }

    function hash(o) {
        if (o === false || o === null || o === undefined) {
            return 0;
        }
        if (typeof o.valueOf === 'function') {
            o = o.valueOf();
            if (o === false || o === null || o === undefined) {
                return 0;
            }
        }
        if (o === true) {
            return 1;
        }
        var type = typeof o;
        if (type === 'number') {
            var h = o | 0;
            if (h !== o) {
                h ^= o * 0xFFFFFFFF;
            }
            while (o > 0xFFFFFFFF) {
                o /= 0xFFFFFFFF;
                h ^= o;
            }
            return smi(h);
        }
        if (type === 'string') {
            return o.length > STRING_HASH_CACHE_MIN_STRLEN ? cachedHashString(o) : hashString(o);
        }
        if (typeof o.hashCode === 'function') {
            return o.hashCode();
        }
        if (type === 'object') {
            return hashJSObj(o);
        }
        if (typeof o.toString === 'function') {
            return hashString(o.toString());
        }
        throw new Error('Value type ' + type + ' cannot be hashed.');
    }

    function cachedHashString(string) {
        var hash = stringHashCache[string];
        if (hash === undefined) {
            hash = hashString(string);
            if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) {
                STRING_HASH_CACHE_SIZE = 0;
                stringHashCache = {};
            }
            STRING_HASH_CACHE_SIZE++;
            stringHashCache[string] = hash;
        }
        return hash;
    }

    // http://jsperf.com/hashing-strings
    function hashString(string) {
        // This is the hash from JVM
        // The hash code for a string is computed as
        // s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
        // where s[i] is the ith character of the string and n is the length of
        // the string. We "mod" the result to make it between 0 (inclusive) and 2^31
        // (exclusive) by dropping high bits.
        var hash = 0;
        for (var ii = 0; ii < string.length; ii++) {
            hash = 31 * hash + string.charCodeAt(ii) | 0;
        }
        return smi(hash);
    }

    function hashJSObj(obj) {
        var hash;
        if (usingWeakMap) {
            hash = weakMap.get(obj);
            if (hash !== undefined) {
                return hash;
            }
        }

        hash = obj[UID_HASH_KEY];
        if (hash !== undefined) {
            return hash;
        }

        if (!canDefineProperty) {
            hash = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
            if (hash !== undefined) {
                return hash;
            }

            hash = getIENodeHash(obj);
            if (hash !== undefined) {
                return hash;
            }
        }

        hash = ++objHashUID;
        if (objHashUID & 0x40000000) {
            objHashUID = 0;
        }

        if (usingWeakMap) {
            weakMap.set(obj, hash);
        } else if (isExtensible !== undefined && isExtensible(obj) === false) {
            throw new Error('Non-extensible objects are not allowed as keys.');
        } else if (canDefineProperty) {
            Object.defineProperty(obj, UID_HASH_KEY, {
                'enumerable': false,
                'configurable': false,
                'writable': false,
                'value': hash
            });
        } else if (obj.propertyIsEnumerable !== undefined &&
                   obj.propertyIsEnumerable === obj.constructor.prototype.propertyIsEnumerable) {
            // Since we can't define a non-enumerable property on the object
            // we'll hijack one of the less-used non-enumerable properties to
            // save our hash on it. Since this is a function it will not show up in
            // `JSON.stringify` which is what we want.
            obj.propertyIsEnumerable = function () {
                return this.constructor.prototype.propertyIsEnumerable.apply(this, arguments);
            };
            obj.propertyIsEnumerable[UID_HASH_KEY] = hash;
        } else if (obj.nodeType !== undefined) {
            // At this point we couldn't get the IE `uniqueID` to use as a hash
            // and we couldn't use a non-enumerable property to exploit the
            // dontEnum bug so we simply add the `UID_HASH_KEY` on the node
            // itself.
            obj[UID_HASH_KEY] = hash;
        } else {
            throw new Error('Unable to set a non-enumerable property on object.');
        }

        return hash;
    }

    // Get references to ES5 object methods.
    var isExtensible = Object.isExtensible;

    // True if Object.defineProperty works as expected. IE8 fails this test.
    var canDefineProperty = (function () {
        try {
            Object.defineProperty({}, '@', {});
            return true;
        } catch (e) {
            return false;
        }
    }());

    // IE has a `uniqueID` property on DOM nodes. We can construct the hash from it
    // and avoid memory leaks from the IE cloneNode bug.
    function getIENodeHash(node) {
        if (node && node.nodeType > 0) {
            switch (node.nodeType) {
                case 1: // Element
                    return node.uniqueID;
                case 9: // Document
                    return node.documentElement && node.documentElement.uniqueID;
            }
        }
    }

    // If possible, use a WeakMap.
    var usingWeakMap = typeof WeakMap === 'function';
    var weakMap;
    if (usingWeakMap) {
        weakMap = new WeakMap();
    }

    var objHashUID = 0;

    var UID_HASH_KEY = '__immutablehash__';
    if (typeof Symbol === 'function') {
        UID_HASH_KEY = Symbol(UID_HASH_KEY);
    }

    var STRING_HASH_CACHE_MIN_STRLEN = 16;
    var STRING_HASH_CACHE_MAX_SIZE = 255;
    var STRING_HASH_CACHE_SIZE = 0;
    var stringHashCache = {};

    function assertNotInfinite(size) {
        invariant(
          size !== Infinity,
          'Cannot perform this action with an infinite size.'
        );
    }

    createClass(Map, KeyedCollection);

    // @pragma Construction

    function Map(value) {
        return value === null || value === undefined ? emptyMap() :
          isMap(value) && !isOrdered(value) ? value :
          emptyMap().withMutations(function (map) {
              var iter = KeyedIterable(value);
              assertNotInfinite(iter.size);
              iter.forEach(function (v, k) { return map.set(k, v) });
          });
    }

    Map.of = function () {
        var keyValues = SLICE$0.call(arguments, 0);
        return emptyMap().withMutations(function (map) {
            for (var i = 0; i < keyValues.length; i += 2) {
                if (i + 1 >= keyValues.length) {
                    throw new Error('Missing value for key: ' + keyValues[i]);
                }
                map.set(keyValues[i], keyValues[i + 1]);
            }
        });
    };

    Map.prototype.toString = function () {
        return this.__toString('Map {', '}');
    };

    // @pragma Access

    Map.prototype.get = function (k, notSetValue) {
        return this._root ?
          this._root.get(0, undefined, k, notSetValue) :
          notSetValue;
    };

    // @pragma Modification

    Map.prototype.set = function (k, v) {
        return updateMap(this, k, v);
    };

    Map.prototype.setIn = function (keyPath, v) {
        return this.updateIn(keyPath, NOT_SET, function () { return v });
    };

    Map.prototype.remove = function (k) {
        return updateMap(this, k, NOT_SET);
    };

    Map.prototype.deleteIn = function (keyPath) {
        return this.updateIn(keyPath, function () { return NOT_SET });
    };

    Map.prototype.update = function (k, notSetValue, updater) {
        return arguments.length === 1 ?
          k(this) :
          this.updateIn([k], notSetValue, updater);
    };

    Map.prototype.updateIn = function (keyPath, notSetValue, updater) {
        if (!updater) {
            updater = notSetValue;
            notSetValue = undefined;
        }
        var updatedValue = updateInDeepMap(
          this,
          forceIterator(keyPath),
          notSetValue,
          updater
        );
        return updatedValue === NOT_SET ? undefined : updatedValue;
    };

    Map.prototype.clear = function () {
        if (this.size === 0) {
            return this;
        }
        if (this.__ownerID) {
            this.size = 0;
            this._root = null;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return emptyMap();
    };

    // @pragma Composition

    Map.prototype.merge = function (/*...iters*/) {
        return mergeIntoMapWith(this, undefined, arguments);
    };

    Map.prototype.mergeWith = function (merger) {
        var iters = SLICE$0.call(arguments, 1);
        return mergeIntoMapWith(this, merger, iters);
    };

    Map.prototype.mergeIn = function (keyPath) {
        var iters = SLICE$0.call(arguments, 1);
        return this.updateIn(
          keyPath,
          emptyMap(),
          function (m) {
              return typeof m.merge === 'function' ?
                m.merge.apply(m, iters) :
                iters[iters.length - 1]
          }
        );
    };

    Map.prototype.mergeDeep = function (/*...iters*/) {
        return mergeIntoMapWith(this, deepMerger, arguments);
    };

    Map.prototype.mergeDeepWith = function (merger) {
        var iters = SLICE$0.call(arguments, 1);
        return mergeIntoMapWith(this, deepMergerWith(merger), iters);
    };

    Map.prototype.mergeDeepIn = function (keyPath) {
        var iters = SLICE$0.call(arguments, 1);
        return this.updateIn(
          keyPath,
          emptyMap(),
          function (m) {
              return typeof m.mergeDeep === 'function' ?
                m.mergeDeep.apply(m, iters) :
                iters[iters.length - 1]
          }
        );
    };

    Map.prototype.sort = function (comparator) {
        // Late binding
        return OrderedMap(sortFactory(this, comparator));
    };

    Map.prototype.sortBy = function (mapper, comparator) {
        // Late binding
        return OrderedMap(sortFactory(this, comparator, mapper));
    };

    // @pragma Mutability

    Map.prototype.withMutations = function (fn) {
        var mutable = this.asMutable();
        fn(mutable);
        return mutable.wasAltered() ? mutable.__ensureOwner(this.__ownerID) : this;
    };

    Map.prototype.asMutable = function () {
        return this.__ownerID ? this : this.__ensureOwner(new OwnerID());
    };

    Map.prototype.asImmutable = function () {
        return this.__ensureOwner();
    };

    Map.prototype.wasAltered = function () {
        return this.__altered;
    };

    Map.prototype.__iterator = function (type, reverse) {
        return new MapIterator(this, type, reverse);
    };

    Map.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        var iterations = 0;
        this._root && this._root.iterate(function (entry) {
            iterations++;
            return fn(entry[1], entry[0], this$0);
        }, reverse);
        return iterations;
    };

    Map.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        if (!ownerID) {
            this.__ownerID = ownerID;
            this.__altered = false;
            return this;
        }
        return makeMap(this.size, this._root, ownerID, this.__hash);
    };


    function isMap(maybeMap) {
        return !!(maybeMap && maybeMap[IS_MAP_SENTINEL]);
    }

    Map.isMap = isMap;

    var IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@';

    var MapPrototype = Map.prototype;
    MapPrototype[IS_MAP_SENTINEL] = true;
    MapPrototype[DELETE] = MapPrototype.remove;
    MapPrototype.removeIn = MapPrototype.deleteIn;


    // #pragma Trie Nodes



    function ArrayMapNode(ownerID, entries) {
        this.ownerID = ownerID;
        this.entries = entries;
    }

    ArrayMapNode.prototype.get = function (shift, keyHash, key, notSetValue) {
        var entries = this.entries;
        for (var ii = 0, len = entries.length; ii < len; ii++) {
            if (is(key, entries[ii][0])) {
                return entries[ii][1];
            }
        }
        return notSetValue;
    };

    ArrayMapNode.prototype.update = function (ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        var removed = value === NOT_SET;

        var entries = this.entries;
        var idx = 0;
        for (var len = entries.length; idx < len; idx++) {
            if (is(key, entries[idx][0])) {
                break;
            }
        }
        var exists = idx < len;

        if (exists ? entries[idx][1] === value : removed) {
            return this;
        }

        SetRef(didAlter);
        (removed || !exists) && SetRef(didChangeSize);

        if (removed && entries.length === 1) {
            return; // undefined
        }

        if (!exists && !removed && entries.length >= MAX_ARRAY_MAP_SIZE) {
            return createNodes(ownerID, entries, key, value);
        }

        var isEditable = ownerID && ownerID === this.ownerID;
        var newEntries = isEditable ? entries : arrCopy(entries);

        if (exists) {
            if (removed) {
                idx === len - 1 ? newEntries.pop() : (newEntries[idx] = newEntries.pop());
            } else {
                newEntries[idx] = [key, value];
            }
        } else {
            newEntries.push([key, value]);
        }

        if (isEditable) {
            this.entries = newEntries;
            return this;
        }

        return new ArrayMapNode(ownerID, newEntries);
    };




    function BitmapIndexedNode(ownerID, bitmap, nodes) {
        this.ownerID = ownerID;
        this.bitmap = bitmap;
        this.nodes = nodes;
    }

    BitmapIndexedNode.prototype.get = function (shift, keyHash, key, notSetValue) {
        if (keyHash === undefined) {
            keyHash = hash(key);
        }
        var bit = (1 << ((shift === 0 ? keyHash : keyHash >>> shift) & MASK));
        var bitmap = this.bitmap;
        return (bitmap & bit) === 0 ? notSetValue :
          this.nodes[popCount(bitmap & (bit - 1))].get(shift + SHIFT, keyHash, key, notSetValue);
    };

    BitmapIndexedNode.prototype.update = function (ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        if (keyHash === undefined) {
            keyHash = hash(key);
        }
        var keyHashFrag = (shift === 0 ? keyHash : keyHash >>> shift) & MASK;
        var bit = 1 << keyHashFrag;
        var bitmap = this.bitmap;
        var exists = (bitmap & bit) !== 0;

        if (!exists && value === NOT_SET) {
            return this;
        }

        var idx = popCount(bitmap & (bit - 1));
        var nodes = this.nodes;
        var node = exists ? nodes[idx] : undefined;
        var newNode = updateNode(node, ownerID, shift + SHIFT, keyHash, key, value, didChangeSize, didAlter);

        if (newNode === node) {
            return this;
        }

        if (!exists && newNode && nodes.length >= MAX_BITMAP_INDEXED_SIZE) {
            return expandNodes(ownerID, nodes, bitmap, keyHashFrag, newNode);
        }

        if (exists && !newNode && nodes.length === 2 && isLeafNode(nodes[idx ^ 1])) {
            return nodes[idx ^ 1];
        }

        if (exists && newNode && nodes.length === 1 && isLeafNode(newNode)) {
            return newNode;
        }

        var isEditable = ownerID && ownerID === this.ownerID;
        var newBitmap = exists ? newNode ? bitmap : bitmap ^ bit : bitmap | bit;
        var newNodes = exists ? newNode ?
          setIn(nodes, idx, newNode, isEditable) :
          spliceOut(nodes, idx, isEditable) :
          spliceIn(nodes, idx, newNode, isEditable);

        if (isEditable) {
            this.bitmap = newBitmap;
            this.nodes = newNodes;
            return this;
        }

        return new BitmapIndexedNode(ownerID, newBitmap, newNodes);
    };




    function HashArrayMapNode(ownerID, count, nodes) {
        this.ownerID = ownerID;
        this.count = count;
        this.nodes = nodes;
    }

    HashArrayMapNode.prototype.get = function (shift, keyHash, key, notSetValue) {
        if (keyHash === undefined) {
            keyHash = hash(key);
        }
        var idx = (shift === 0 ? keyHash : keyHash >>> shift) & MASK;
        var node = this.nodes[idx];
        return node ? node.get(shift + SHIFT, keyHash, key, notSetValue) : notSetValue;
    };

    HashArrayMapNode.prototype.update = function (ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        if (keyHash === undefined) {
            keyHash = hash(key);
        }
        var idx = (shift === 0 ? keyHash : keyHash >>> shift) & MASK;
        var removed = value === NOT_SET;
        var nodes = this.nodes;
        var node = nodes[idx];

        if (removed && !node) {
            return this;
        }

        var newNode = updateNode(node, ownerID, shift + SHIFT, keyHash, key, value, didChangeSize, didAlter);
        if (newNode === node) {
            return this;
        }

        var newCount = this.count;
        if (!node) {
            newCount++;
        } else if (!newNode) {
            newCount--;
            if (newCount < MIN_HASH_ARRAY_MAP_SIZE) {
                return packNodes(ownerID, nodes, newCount, idx);
            }
        }

        var isEditable = ownerID && ownerID === this.ownerID;
        var newNodes = setIn(nodes, idx, newNode, isEditable);

        if (isEditable) {
            this.count = newCount;
            this.nodes = newNodes;
            return this;
        }

        return new HashArrayMapNode(ownerID, newCount, newNodes);
    };




    function HashCollisionNode(ownerID, keyHash, entries) {
        this.ownerID = ownerID;
        this.keyHash = keyHash;
        this.entries = entries;
    }

    HashCollisionNode.prototype.get = function (shift, keyHash, key, notSetValue) {
        var entries = this.entries;
        for (var ii = 0, len = entries.length; ii < len; ii++) {
            if (is(key, entries[ii][0])) {
                return entries[ii][1];
            }
        }
        return notSetValue;
    };

    HashCollisionNode.prototype.update = function (ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        if (keyHash === undefined) {
            keyHash = hash(key);
        }

        var removed = value === NOT_SET;

        if (keyHash !== this.keyHash) {
            if (removed) {
                return this;
            }
            SetRef(didAlter);
            SetRef(didChangeSize);
            return mergeIntoNode(this, ownerID, shift, keyHash, [key, value]);
        }

        var entries = this.entries;
        var idx = 0;
        for (var len = entries.length; idx < len; idx++) {
            if (is(key, entries[idx][0])) {
                break;
            }
        }
        var exists = idx < len;

        if (exists ? entries[idx][1] === value : removed) {
            return this;
        }

        SetRef(didAlter);
        (removed || !exists) && SetRef(didChangeSize);

        if (removed && len === 2) {
            return new ValueNode(ownerID, this.keyHash, entries[idx ^ 1]);
        }

        var isEditable = ownerID && ownerID === this.ownerID;
        var newEntries = isEditable ? entries : arrCopy(entries);

        if (exists) {
            if (removed) {
                idx === len - 1 ? newEntries.pop() : (newEntries[idx] = newEntries.pop());
            } else {
                newEntries[idx] = [key, value];
            }
        } else {
            newEntries.push([key, value]);
        }

        if (isEditable) {
            this.entries = newEntries;
            return this;
        }

        return new HashCollisionNode(ownerID, this.keyHash, newEntries);
    };




    function ValueNode(ownerID, keyHash, entry) {
        this.ownerID = ownerID;
        this.keyHash = keyHash;
        this.entry = entry;
    }

    ValueNode.prototype.get = function (shift, keyHash, key, notSetValue) {
        return is(key, this.entry[0]) ? this.entry[1] : notSetValue;
    };

    ValueNode.prototype.update = function (ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        var removed = value === NOT_SET;
        var keyMatch = is(key, this.entry[0]);
        if (keyMatch ? value === this.entry[1] : removed) {
            return this;
        }

        SetRef(didAlter);

        if (removed) {
            SetRef(didChangeSize);
            return; // undefined
        }

        if (keyMatch) {
            if (ownerID && ownerID === this.ownerID) {
                this.entry[1] = value;
                return this;
            }
            return new ValueNode(ownerID, this.keyHash, [key, value]);
        }

        SetRef(didChangeSize);
        return mergeIntoNode(this, ownerID, shift, hash(key), [key, value]);
    };



    // #pragma Iterators

    ArrayMapNode.prototype.iterate =
    HashCollisionNode.prototype.iterate = function (fn, reverse) {
        var entries = this.entries;
        for (var ii = 0, maxIndex = entries.length - 1; ii <= maxIndex; ii++) {
            if (fn(entries[reverse ? maxIndex - ii : ii]) === false) {
                return false;
            }
        }
    }

    BitmapIndexedNode.prototype.iterate =
    HashArrayMapNode.prototype.iterate = function (fn, reverse) {
        var nodes = this.nodes;
        for (var ii = 0, maxIndex = nodes.length - 1; ii <= maxIndex; ii++) {
            var node = nodes[reverse ? maxIndex - ii : ii];
            if (node && node.iterate(fn, reverse) === false) {
                return false;
            }
        }
    }

    ValueNode.prototype.iterate = function (fn, reverse) {
        return fn(this.entry);
    }

    createClass(MapIterator, Iterator);

    function MapIterator(map, type, reverse) {
        this._type = type;
        this._reverse = reverse;
        this._stack = map._root && mapIteratorFrame(map._root);
    }

    MapIterator.prototype.next = function () {
        var type = this._type;
        var stack = this._stack;
        while (stack) {
            var node = stack.node;
            var index = stack.index++;
            var maxIndex;
            if (node.entry) {
                if (index === 0) {
                    return mapIteratorValue(type, node.entry);
                }
            } else if (node.entries) {
                maxIndex = node.entries.length - 1;
                if (index <= maxIndex) {
                    return mapIteratorValue(type, node.entries[this._reverse ? maxIndex - index : index]);
                }
            } else {
                maxIndex = node.nodes.length - 1;
                if (index <= maxIndex) {
                    var subNode = node.nodes[this._reverse ? maxIndex - index : index];
                    if (subNode) {
                        if (subNode.entry) {
                            return mapIteratorValue(type, subNode.entry);
                        }
                        stack = this._stack = mapIteratorFrame(subNode, stack);
                    }
                    continue;
                }
            }
            stack = this._stack = this._stack.__prev;
        }
        return iteratorDone();
    };


    function mapIteratorValue(type, entry) {
        return iteratorValue(type, entry[0], entry[1]);
    }

    function mapIteratorFrame(node, prev) {
        return {
            node: node,
            index: 0,
            __prev: prev
        };
    }

    function makeMap(size, root, ownerID, hash) {
        var map = Object.create(MapPrototype);
        map.size = size;
        map._root = root;
        map.__ownerID = ownerID;
        map.__hash = hash;
        map.__altered = false;
        return map;
    }

    var EMPTY_MAP;
    function emptyMap() {
        return EMPTY_MAP || (EMPTY_MAP = makeMap(0));
    }

    function updateMap(map, k, v) {
        var newRoot;
        var newSize;
        if (!map._root) {
            if (v === NOT_SET) {
                return map;
            }
            newSize = 1;
            newRoot = new ArrayMapNode(map.__ownerID, [[k, v]]);
        } else {
            var didChangeSize = MakeRef(CHANGE_LENGTH);
            var didAlter = MakeRef(DID_ALTER);
            newRoot = updateNode(map._root, map.__ownerID, 0, undefined, k, v, didChangeSize, didAlter);
            if (!didAlter.value) {
                return map;
            }
            newSize = map.size + (didChangeSize.value ? v === NOT_SET ? -1 : 1 : 0);
        }
        if (map.__ownerID) {
            map.size = newSize;
            map._root = newRoot;
            map.__hash = undefined;
            map.__altered = true;
            return map;
        }
        return newRoot ? makeMap(newSize, newRoot) : emptyMap();
    }

    function updateNode(node, ownerID, shift, keyHash, key, value, didChangeSize, didAlter) {
        if (!node) {
            if (value === NOT_SET) {
                return node;
            }
            SetRef(didAlter);
            SetRef(didChangeSize);
            return new ValueNode(ownerID, keyHash, [key, value]);
        }
        return node.update(ownerID, shift, keyHash, key, value, didChangeSize, didAlter);
    }

    function isLeafNode(node) {
        return node.constructor === ValueNode || node.constructor === HashCollisionNode;
    }

    function mergeIntoNode(node, ownerID, shift, keyHash, entry) {
        if (node.keyHash === keyHash) {
            return new HashCollisionNode(ownerID, keyHash, [node.entry, entry]);
        }

        var idx1 = (shift === 0 ? node.keyHash : node.keyHash >>> shift) & MASK;
        var idx2 = (shift === 0 ? keyHash : keyHash >>> shift) & MASK;

        var newNode;
        var nodes = idx1 === idx2 ?
          [mergeIntoNode(node, ownerID, shift + SHIFT, keyHash, entry)] :
          ((newNode = new ValueNode(ownerID, keyHash, entry)), idx1 < idx2 ? [node, newNode] : [newNode, node]);

        return new BitmapIndexedNode(ownerID, (1 << idx1) | (1 << idx2), nodes);
    }

    function createNodes(ownerID, entries, key, value) {
        if (!ownerID) {
            ownerID = new OwnerID();
        }
        var node = new ValueNode(ownerID, hash(key), [key, value]);
        for (var ii = 0; ii < entries.length; ii++) {
            var entry = entries[ii];
            node = node.update(ownerID, 0, undefined, entry[0], entry[1]);
        }
        return node;
    }

    function packNodes(ownerID, nodes, count, excluding) {
        var bitmap = 0;
        var packedII = 0;
        var packedNodes = new Array(count);
        for (var ii = 0, bit = 1, len = nodes.length; ii < len; ii++, bit <<= 1) {
            var node = nodes[ii];
            if (node !== undefined && ii !== excluding) {
                bitmap |= bit;
                packedNodes[packedII++] = node;
            }
        }
        return new BitmapIndexedNode(ownerID, bitmap, packedNodes);
    }

    function expandNodes(ownerID, nodes, bitmap, including, node) {
        var count = 0;
        var expandedNodes = new Array(SIZE);
        for (var ii = 0; bitmap !== 0; ii++, bitmap >>>= 1) {
            expandedNodes[ii] = bitmap & 1 ? nodes[count++] : undefined;
        }
        expandedNodes[including] = node;
        return new HashArrayMapNode(ownerID, count + 1, expandedNodes);
    }

    function mergeIntoMapWith(map, merger, iterables) {
        var iters = [];
        for (var ii = 0; ii < iterables.length; ii++) {
            var value = iterables[ii];
            var iter = KeyedIterable(value);
            if (!isIterable(value)) {
                iter = iter.map(function (v) { return fromJS(v) });
            }
            iters.push(iter);
        }
        return mergeIntoCollectionWith(map, merger, iters);
    }

    function deepMerger(existing, value, key) {
        return existing && existing.mergeDeep && isIterable(value) ?
          existing.mergeDeep(value) :
          is(existing, value) ? existing : value;
    }

    function deepMergerWith(merger) {
        return function (existing, value, key) {
            if (existing && existing.mergeDeepWith && isIterable(value)) {
                return existing.mergeDeepWith(merger, value);
            }
            var nextValue = merger(existing, value, key);
            return is(existing, nextValue) ? existing : nextValue;
        };
    }

    function mergeIntoCollectionWith(collection, merger, iters) {
        iters = iters.filter(function (x) { return x.size !== 0 });
        if (iters.length === 0) {
            return collection;
        }
        if (collection.size === 0 && !collection.__ownerID && iters.length === 1) {
            return collection.constructor(iters[0]);
        }
        return collection.withMutations(function (collection) {
            var mergeIntoMap = merger ?
              function (value, key) {
                  collection.update(key, NOT_SET, function (existing)
                  { return existing === NOT_SET ? value : merger(existing, value, key) }
                  );
              } :
              function (value, key) {
                  collection.set(key, value);
              }
            for (var ii = 0; ii < iters.length; ii++) {
                iters[ii].forEach(mergeIntoMap);
            }
        });
    }

    function updateInDeepMap(existing, keyPathIter, notSetValue, updater) {
        var isNotSet = existing === NOT_SET;
        var step = keyPathIter.next();
        if (step.done) {
            var existingValue = isNotSet ? notSetValue : existing;
            var newValue = updater(existingValue);
            return newValue === existingValue ? existing : newValue;
        }
        invariant(
          isNotSet || (existing && existing.set),
          'invalid keyPath'
        );
        var key = step.value;
        var nextExisting = isNotSet ? NOT_SET : existing.get(key, NOT_SET);
        var nextUpdated = updateInDeepMap(
          nextExisting,
          keyPathIter,
          notSetValue,
          updater
        );
        return nextUpdated === nextExisting ? existing :
          nextUpdated === NOT_SET ? existing.remove(key) :
          (isNotSet ? emptyMap() : existing).set(key, nextUpdated);
    }

    function popCount(x) {
        x = x - ((x >> 1) & 0x55555555);
        x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
        x = (x + (x >> 4)) & 0x0f0f0f0f;
        x = x + (x >> 8);
        x = x + (x >> 16);
        return x & 0x7f;
    }

    function setIn(array, idx, val, canEdit) {
        var newArray = canEdit ? array : arrCopy(array);
        newArray[idx] = val;
        return newArray;
    }

    function spliceIn(array, idx, val, canEdit) {
        var newLen = array.length + 1;
        if (canEdit && idx + 1 === newLen) {
            array[idx] = val;
            return array;
        }
        var newArray = new Array(newLen);
        var after = 0;
        for (var ii = 0; ii < newLen; ii++) {
            if (ii === idx) {
                newArray[ii] = val;
                after = -1;
            } else {
                newArray[ii] = array[ii + after];
            }
        }
        return newArray;
    }

    function spliceOut(array, idx, canEdit) {
        var newLen = array.length - 1;
        if (canEdit && idx === newLen) {
            array.pop();
            return array;
        }
        var newArray = new Array(newLen);
        var after = 0;
        for (var ii = 0; ii < newLen; ii++) {
            if (ii === idx) {
                after = 1;
            }
            newArray[ii] = array[ii + after];
        }
        return newArray;
    }

    var MAX_ARRAY_MAP_SIZE = SIZE / 4;
    var MAX_BITMAP_INDEXED_SIZE = SIZE / 2;
    var MIN_HASH_ARRAY_MAP_SIZE = SIZE / 4;

    createClass(List, IndexedCollection);

    // @pragma Construction

    function List(value) {
        var empty = emptyList();
        if (value === null || value === undefined) {
            return empty;
        }
        if (isList(value)) {
            return value;
        }
        var iter = IndexedIterable(value);
        var size = iter.size;
        if (size === 0) {
            return empty;
        }
        assertNotInfinite(size);
        if (size > 0 && size < SIZE) {
            return makeList(0, size, SHIFT, null, new VNode(iter.toArray()));
        }
        return empty.withMutations(function (list) {
            list.setSize(size);
            iter.forEach(function (v, i) { return list.set(i, v) });
        });
    }

    List.of = function (/*...values*/) {
        return this(arguments);
    };

    List.prototype.toString = function () {
        return this.__toString('List [', ']');
    };

    // @pragma Access

    List.prototype.get = function (index, notSetValue) {
        index = wrapIndex(this, index);
        if (index >= 0 && index < this.size) {
            index += this._origin;
            var node = listNodeFor(this, index);
            return node && node.array[index & MASK];
        }
        return notSetValue;
    };

    // @pragma Modification

    List.prototype.set = function (index, value) {
        return updateList(this, index, value);
    };

    List.prototype.remove = function (index) {
        return !this.has(index) ? this :
          index === 0 ? this.shift() :
          index === this.size - 1 ? this.pop() :
          this.splice(index, 1);
    };

    List.prototype.insert = function (index, value) {
        return this.splice(index, 0, value);
    };

    List.prototype.clear = function () {
        if (this.size === 0) {
            return this;
        }
        if (this.__ownerID) {
            this.size = this._origin = this._capacity = 0;
            this._level = SHIFT;
            this._root = this._tail = null;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return emptyList();
    };

    List.prototype.push = function (/*...values*/) {
        var values = arguments;
        var oldSize = this.size;
        return this.withMutations(function (list) {
            setListBounds(list, 0, oldSize + values.length);
            for (var ii = 0; ii < values.length; ii++) {
                list.set(oldSize + ii, values[ii]);
            }
        });
    };

    List.prototype.pop = function () {
        return setListBounds(this, 0, -1);
    };

    List.prototype.unshift = function (/*...values*/) {
        var values = arguments;
        return this.withMutations(function (list) {
            setListBounds(list, -values.length);
            for (var ii = 0; ii < values.length; ii++) {
                list.set(ii, values[ii]);
            }
        });
    };

    List.prototype.shift = function () {
        return setListBounds(this, 1);
    };

    // @pragma Composition

    List.prototype.merge = function (/*...iters*/) {
        return mergeIntoListWith(this, undefined, arguments);
    };

    List.prototype.mergeWith = function (merger) {
        var iters = SLICE$0.call(arguments, 1);
        return mergeIntoListWith(this, merger, iters);
    };

    List.prototype.mergeDeep = function (/*...iters*/) {
        return mergeIntoListWith(this, deepMerger, arguments);
    };

    List.prototype.mergeDeepWith = function (merger) {
        var iters = SLICE$0.call(arguments, 1);
        return mergeIntoListWith(this, deepMergerWith(merger), iters);
    };

    List.prototype.setSize = function (size) {
        return setListBounds(this, 0, size);
    };

    // @pragma Iteration

    List.prototype.slice = function (begin, end) {
        var size = this.size;
        if (wholeSlice(begin, end, size)) {
            return this;
        }
        return setListBounds(
          this,
          resolveBegin(begin, size),
          resolveEnd(end, size)
        );
    };

    List.prototype.__iterator = function (type, reverse) {
        var index = 0;
        var values = iterateList(this, reverse);
        return new Iterator(function () {
            var value = values();
            return value === DONE ?
              iteratorDone() :
              iteratorValue(type, index++, value);
        });
    };

    List.prototype.__iterate = function (fn, reverse) {
        var index = 0;
        var values = iterateList(this, reverse);
        var value;
        while ((value = values()) !== DONE) {
            if (fn(value, index++, this) === false) {
                break;
            }
        }
        return index;
    };

    List.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        if (!ownerID) {
            this.__ownerID = ownerID;
            return this;
        }
        return makeList(this._origin, this._capacity, this._level, this._root, this._tail, ownerID, this.__hash);
    };


    function isList(maybeList) {
        return !!(maybeList && maybeList[IS_LIST_SENTINEL]);
    }

    List.isList = isList;

    var IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@';

    var ListPrototype = List.prototype;
    ListPrototype[IS_LIST_SENTINEL] = true;
    ListPrototype[DELETE] = ListPrototype.remove;
    ListPrototype.setIn = MapPrototype.setIn;
    ListPrototype.deleteIn =
    ListPrototype.removeIn = MapPrototype.removeIn;
    ListPrototype.update = MapPrototype.update;
    ListPrototype.updateIn = MapPrototype.updateIn;
    ListPrototype.mergeIn = MapPrototype.mergeIn;
    ListPrototype.mergeDeepIn = MapPrototype.mergeDeepIn;
    ListPrototype.withMutations = MapPrototype.withMutations;
    ListPrototype.asMutable = MapPrototype.asMutable;
    ListPrototype.asImmutable = MapPrototype.asImmutable;
    ListPrototype.wasAltered = MapPrototype.wasAltered;



    function VNode(array, ownerID) {
        this.array = array;
        this.ownerID = ownerID;
    }

    // TODO: seems like these methods are very similar

    VNode.prototype.removeBefore = function (ownerID, level, index) {
        if (index === level ? 1 << level : 0 || this.array.length === 0) {
            return this;
        }
        var originIndex = (index >>> level) & MASK;
        if (originIndex >= this.array.length) {
            return new VNode([], ownerID);
        }
        var removingFirst = originIndex === 0;
        var newChild;
        if (level > 0) {
            var oldChild = this.array[originIndex];
            newChild = oldChild && oldChild.removeBefore(ownerID, level - SHIFT, index);
            if (newChild === oldChild && removingFirst) {
                return this;
            }
        }
        if (removingFirst && !newChild) {
            return this;
        }
        var editable = editableVNode(this, ownerID);
        if (!removingFirst) {
            for (var ii = 0; ii < originIndex; ii++) {
                editable.array[ii] = undefined;
            }
        }
        if (newChild) {
            editable.array[originIndex] = newChild;
        }
        return editable;
    };

    VNode.prototype.removeAfter = function (ownerID, level, index) {
        if (index === (level ? 1 << level : 0) || this.array.length === 0) {
            return this;
        }
        var sizeIndex = ((index - 1) >>> level) & MASK;
        if (sizeIndex >= this.array.length) {
            return this;
        }

        var newChild;
        if (level > 0) {
            var oldChild = this.array[sizeIndex];
            newChild = oldChild && oldChild.removeAfter(ownerID, level - SHIFT, index);
            if (newChild === oldChild && sizeIndex === this.array.length - 1) {
                return this;
            }
        }

        var editable = editableVNode(this, ownerID);
        editable.array.splice(sizeIndex + 1);
        if (newChild) {
            editable.array[sizeIndex] = newChild;
        }
        return editable;
    };



    var DONE = {};

    function iterateList(list, reverse) {
        var left = list._origin;
        var right = list._capacity;
        var tailPos = getTailOffset(right);
        var tail = list._tail;

        return iterateNodeOrLeaf(list._root, list._level, 0);

        function iterateNodeOrLeaf(node, level, offset) {
            return level === 0 ?
              iterateLeaf(node, offset) :
              iterateNode(node, level, offset);
        }

        function iterateLeaf(node, offset) {
            var array = offset === tailPos ? tail && tail.array : node && node.array;
            var from = offset > left ? 0 : left - offset;
            var to = right - offset;
            if (to > SIZE) {
                to = SIZE;
            }
            return function () {
                if (from === to) {
                    return DONE;
                }
                var idx = reverse ? --to : from++;
                return array && array[idx];
            };
        }

        function iterateNode(node, level, offset) {
            var values;
            var array = node && node.array;
            var from = offset > left ? 0 : (left - offset) >> level;
            var to = ((right - offset) >> level) + 1;
            if (to > SIZE) {
                to = SIZE;
            }
            return function () {
                do {
                    if (values) {
                        var value = values();
                        if (value !== DONE) {
                            return value;
                        }
                        values = null;
                    }
                    if (from === to) {
                        return DONE;
                    }
                    var idx = reverse ? --to : from++;
                    values = iterateNodeOrLeaf(
                      array && array[idx], level - SHIFT, offset + (idx << level)
                    );
                } while (true);
            };
        }
    }

    function makeList(origin, capacity, level, root, tail, ownerID, hash) {
        var list = Object.create(ListPrototype);
        list.size = capacity - origin;
        list._origin = origin;
        list._capacity = capacity;
        list._level = level;
        list._root = root;
        list._tail = tail;
        list.__ownerID = ownerID;
        list.__hash = hash;
        list.__altered = false;
        return list;
    }

    var EMPTY_LIST;
    function emptyList() {
        return EMPTY_LIST || (EMPTY_LIST = makeList(0, 0, SHIFT));
    }

    function updateList(list, index, value) {
        index = wrapIndex(list, index);

        if (index !== index) {
            return list;
        }

        if (index >= list.size || index < 0) {
            return list.withMutations(function (list) {
                index < 0 ?
                  setListBounds(list, index).set(0, value) :
                  setListBounds(list, 0, index + 1).set(index, value)
            });
        }

        index += list._origin;

        var newTail = list._tail;
        var newRoot = list._root;
        var didAlter = MakeRef(DID_ALTER);
        if (index >= getTailOffset(list._capacity)) {
            newTail = updateVNode(newTail, list.__ownerID, 0, index, value, didAlter);
        } else {
            newRoot = updateVNode(newRoot, list.__ownerID, list._level, index, value, didAlter);
        }

        if (!didAlter.value) {
            return list;
        }

        if (list.__ownerID) {
            list._root = newRoot;
            list._tail = newTail;
            list.__hash = undefined;
            list.__altered = true;
            return list;
        }
        return makeList(list._origin, list._capacity, list._level, newRoot, newTail);
    }

    function updateVNode(node, ownerID, level, index, value, didAlter) {
        var idx = (index >>> level) & MASK;
        var nodeHas = node && idx < node.array.length;
        if (!nodeHas && value === undefined) {
            return node;
        }

        var newNode;

        if (level > 0) {
            var lowerNode = node && node.array[idx];
            var newLowerNode = updateVNode(lowerNode, ownerID, level - SHIFT, index, value, didAlter);
            if (newLowerNode === lowerNode) {
                return node;
            }
            newNode = editableVNode(node, ownerID);
            newNode.array[idx] = newLowerNode;
            return newNode;
        }

        if (nodeHas && node.array[idx] === value) {
            return node;
        }

        SetRef(didAlter);

        newNode = editableVNode(node, ownerID);
        if (value === undefined && idx === newNode.array.length - 1) {
            newNode.array.pop();
        } else {
            newNode.array[idx] = value;
        }
        return newNode;
    }

    function editableVNode(node, ownerID) {
        if (ownerID && node && ownerID === node.ownerID) {
            return node;
        }
        return new VNode(node ? node.array.slice() : [], ownerID);
    }

    function listNodeFor(list, rawIndex) {
        if (rawIndex >= getTailOffset(list._capacity)) {
            return list._tail;
        }
        if (rawIndex < 1 << (list._level + SHIFT)) {
            var node = list._root;
            var level = list._level;
            while (node && level > 0) {
                node = node.array[(rawIndex >>> level) & MASK];
                level -= SHIFT;
            }
            return node;
        }
    }

    function setListBounds(list, begin, end) {
        // Sanitize begin & end using this shorthand for ToInt32(argument)
        // http://www.ecma-international.org/ecma-262/6.0/#sec-toint32
        if (begin !== undefined) {
            begin = begin | 0;
        }
        if (end !== undefined) {
            end = end | 0;
        }
        var owner = list.__ownerID || new OwnerID();
        var oldOrigin = list._origin;
        var oldCapacity = list._capacity;
        var newOrigin = oldOrigin + begin;
        var newCapacity = end === undefined ? oldCapacity : end < 0 ? oldCapacity + end : oldOrigin + end;
        if (newOrigin === oldOrigin && newCapacity === oldCapacity) {
            return list;
        }

        // If it's going to end after it starts, it's empty.
        if (newOrigin >= newCapacity) {
            return list.clear();
        }

        var newLevel = list._level;
        var newRoot = list._root;

        // New origin might need creating a higher root.
        var offsetShift = 0;
        while (newOrigin + offsetShift < 0) {
            newRoot = new VNode(newRoot && newRoot.array.length ? [undefined, newRoot] : [], owner);
            newLevel += SHIFT;
            offsetShift += 1 << newLevel;
        }
        if (offsetShift) {
            newOrigin += offsetShift;
            oldOrigin += offsetShift;
            newCapacity += offsetShift;
            oldCapacity += offsetShift;
        }

        var oldTailOffset = getTailOffset(oldCapacity);
        var newTailOffset = getTailOffset(newCapacity);

        // New size might need creating a higher root.
        while (newTailOffset >= 1 << (newLevel + SHIFT)) {
            newRoot = new VNode(newRoot && newRoot.array.length ? [newRoot] : [], owner);
            newLevel += SHIFT;
        }

        // Locate or create the new tail.
        var oldTail = list._tail;
        var newTail = newTailOffset < oldTailOffset ?
          listNodeFor(list, newCapacity - 1) :
          newTailOffset > oldTailOffset ? new VNode([], owner) : oldTail;

        // Merge Tail into tree.
        if (oldTail && newTailOffset > oldTailOffset && newOrigin < oldCapacity && oldTail.array.length) {
            newRoot = editableVNode(newRoot, owner);
            var node = newRoot;
            for (var level = newLevel; level > SHIFT; level -= SHIFT) {
                var idx = (oldTailOffset >>> level) & MASK;
                node = node.array[idx] = editableVNode(node.array[idx], owner);
            }
            node.array[(oldTailOffset >>> SHIFT) & MASK] = oldTail;
        }

        // If the size has been reduced, there's a chance the tail needs to be trimmed.
        if (newCapacity < oldCapacity) {
            newTail = newTail && newTail.removeAfter(owner, 0, newCapacity);
        }

        // If the new origin is within the tail, then we do not need a root.
        if (newOrigin >= newTailOffset) {
            newOrigin -= newTailOffset;
            newCapacity -= newTailOffset;
            newLevel = SHIFT;
            newRoot = null;
            newTail = newTail && newTail.removeBefore(owner, 0, newOrigin);

            // Otherwise, if the root has been trimmed, garbage collect.
        } else if (newOrigin > oldOrigin || newTailOffset < oldTailOffset) {
            offsetShift = 0;

            // Identify the new top root node of the subtree of the old root.
            while (newRoot) {
                var beginIndex = (newOrigin >>> newLevel) & MASK;
                if (beginIndex !== (newTailOffset >>> newLevel) & MASK) {
                    break;
                }
                if (beginIndex) {
                    offsetShift += (1 << newLevel) * beginIndex;
                }
                newLevel -= SHIFT;
                newRoot = newRoot.array[beginIndex];
            }

            // Trim the new sides of the new root.
            if (newRoot && newOrigin > oldOrigin) {
                newRoot = newRoot.removeBefore(owner, newLevel, newOrigin - offsetShift);
            }
            if (newRoot && newTailOffset < oldTailOffset) {
                newRoot = newRoot.removeAfter(owner, newLevel, newTailOffset - offsetShift);
            }
            if (offsetShift) {
                newOrigin -= offsetShift;
                newCapacity -= offsetShift;
            }
        }

        if (list.__ownerID) {
            list.size = newCapacity - newOrigin;
            list._origin = newOrigin;
            list._capacity = newCapacity;
            list._level = newLevel;
            list._root = newRoot;
            list._tail = newTail;
            list.__hash = undefined;
            list.__altered = true;
            return list;
        }
        return makeList(newOrigin, newCapacity, newLevel, newRoot, newTail);
    }

    function mergeIntoListWith(list, merger, iterables) {
        var iters = [];
        var maxSize = 0;
        for (var ii = 0; ii < iterables.length; ii++) {
            var value = iterables[ii];
            var iter = IndexedIterable(value);
            if (iter.size > maxSize) {
                maxSize = iter.size;
            }
            if (!isIterable(value)) {
                iter = iter.map(function (v) { return fromJS(v) });
            }
            iters.push(iter);
        }
        if (maxSize > list.size) {
            list = list.setSize(maxSize);
        }
        return mergeIntoCollectionWith(list, merger, iters);
    }

    function getTailOffset(size) {
        return size < SIZE ? 0 : (((size - 1) >>> SHIFT) << SHIFT);
    }

    createClass(OrderedMap, Map);

    // @pragma Construction

    function OrderedMap(value) {
        return value === null || value === undefined ? emptyOrderedMap() :
          isOrderedMap(value) ? value :
          emptyOrderedMap().withMutations(function (map) {
              var iter = KeyedIterable(value);
              assertNotInfinite(iter.size);
              iter.forEach(function (v, k) { return map.set(k, v) });
          });
    }

    OrderedMap.of = function (/*...values*/) {
        return this(arguments);
    };

    OrderedMap.prototype.toString = function () {
        return this.__toString('OrderedMap {', '}');
    };

    // @pragma Access

    OrderedMap.prototype.get = function (k, notSetValue) {
        var index = this._map.get(k);
        return index !== undefined ? this._list.get(index)[1] : notSetValue;
    };

    // @pragma Modification

    OrderedMap.prototype.clear = function () {
        if (this.size === 0) {
            return this;
        }
        if (this.__ownerID) {
            this.size = 0;
            this._map.clear();
            this._list.clear();
            return this;
        }
        return emptyOrderedMap();
    };

    OrderedMap.prototype.set = function (k, v) {
        return updateOrderedMap(this, k, v);
    };

    OrderedMap.prototype.remove = function (k) {
        return updateOrderedMap(this, k, NOT_SET);
    };

    OrderedMap.prototype.wasAltered = function () {
        return this._map.wasAltered() || this._list.wasAltered();
    };

    OrderedMap.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        return this._list.__iterate(
          function (entry) { return entry && fn(entry[1], entry[0], this$0) },
          reverse
        );
    };

    OrderedMap.prototype.__iterator = function (type, reverse) {
        return this._list.fromEntrySeq().__iterator(type, reverse);
    };

    OrderedMap.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        var newMap = this._map.__ensureOwner(ownerID);
        var newList = this._list.__ensureOwner(ownerID);
        if (!ownerID) {
            this.__ownerID = ownerID;
            this._map = newMap;
            this._list = newList;
            return this;
        }
        return makeOrderedMap(newMap, newList, ownerID, this.__hash);
    };


    function isOrderedMap(maybeOrderedMap) {
        return isMap(maybeOrderedMap) && isOrdered(maybeOrderedMap);
    }

    OrderedMap.isOrderedMap = isOrderedMap;

    OrderedMap.prototype[IS_ORDERED_SENTINEL] = true;
    OrderedMap.prototype[DELETE] = OrderedMap.prototype.remove;



    function makeOrderedMap(map, list, ownerID, hash) {
        var omap = Object.create(OrderedMap.prototype);
        omap.size = map ? map.size : 0;
        omap._map = map;
        omap._list = list;
        omap.__ownerID = ownerID;
        omap.__hash = hash;
        return omap;
    }

    var EMPTY_ORDERED_MAP;
    function emptyOrderedMap() {
        return EMPTY_ORDERED_MAP || (EMPTY_ORDERED_MAP = makeOrderedMap(emptyMap(), emptyList()));
    }

    function updateOrderedMap(omap, k, v) {
        var map = omap._map;
        var list = omap._list;
        var i = map.get(k);
        var has = i !== undefined;
        var newMap;
        var newList;
        if (v === NOT_SET) { // removed
            if (!has) {
                return omap;
            }
            if (list.size >= SIZE && list.size >= map.size * 2) {
                newList = list.filter(function (entry, idx) { return entry !== undefined && i !== idx });
                newMap = newList.toKeyedSeq().map(function (entry) { return entry[0] }).flip().toMap();
                if (omap.__ownerID) {
                    newMap.__ownerID = newList.__ownerID = omap.__ownerID;
                }
            } else {
                newMap = map.remove(k);
                newList = i === list.size - 1 ? list.pop() : list.set(i, undefined);
            }
        } else {
            if (has) {
                if (v === list.get(i)[1]) {
                    return omap;
                }
                newMap = map;
                newList = list.set(i, [k, v]);
            } else {
                newMap = map.set(k, list.size);
                newList = list.set(list.size, [k, v]);
            }
        }
        if (omap.__ownerID) {
            omap.size = newMap.size;
            omap._map = newMap;
            omap._list = newList;
            omap.__hash = undefined;
            return omap;
        }
        return makeOrderedMap(newMap, newList);
    }

    createClass(ToKeyedSequence, KeyedSeq);
    function ToKeyedSequence(indexed, useKeys) {
        this._iter = indexed;
        this._useKeys = useKeys;
        this.size = indexed.size;
    }

    ToKeyedSequence.prototype.get = function (key, notSetValue) {
        return this._iter.get(key, notSetValue);
    };

    ToKeyedSequence.prototype.has = function (key) {
        return this._iter.has(key);
    };

    ToKeyedSequence.prototype.valueSeq = function () {
        return this._iter.valueSeq();
    };

    ToKeyedSequence.prototype.reverse = function () {
        var this$0 = this;
        var reversedSequence = reverseFactory(this, true);
        if (!this._useKeys) {
            reversedSequence.valueSeq = function () { return this$0._iter.toSeq().reverse() };
        }
        return reversedSequence;
    };

    ToKeyedSequence.prototype.map = function (mapper, context) {
        var this$0 = this;
        var mappedSequence = mapFactory(this, mapper, context);
        if (!this._useKeys) {
            mappedSequence.valueSeq = function () { return this$0._iter.toSeq().map(mapper, context) };
        }
        return mappedSequence;
    };

    ToKeyedSequence.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        var ii;
        return this._iter.__iterate(
          this._useKeys ?
            function (v, k) { return fn(v, k, this$0) } :
            ((ii = reverse ? resolveSize(this) : 0),
              function (v) { return fn(v, reverse ? --ii : ii++, this$0) }),
          reverse
        );
    };

    ToKeyedSequence.prototype.__iterator = function (type, reverse) {
        if (this._useKeys) {
            return this._iter.__iterator(type, reverse);
        }
        var iterator = this._iter.__iterator(ITERATE_VALUES, reverse);
        var ii = reverse ? resolveSize(this) : 0;
        return new Iterator(function () {
            var step = iterator.next();
            return step.done ? step :
              iteratorValue(type, reverse ? --ii : ii++, step.value, step);
        });
    };

    ToKeyedSequence.prototype[IS_ORDERED_SENTINEL] = true;


    createClass(ToIndexedSequence, IndexedSeq);
    function ToIndexedSequence(iter) {
        this._iter = iter;
        this.size = iter.size;
    }

    ToIndexedSequence.prototype.includes = function (value) {
        return this._iter.includes(value);
    };

    ToIndexedSequence.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        var iterations = 0;
        return this._iter.__iterate(function (v) { return fn(v, iterations++, this$0) }, reverse);
    };

    ToIndexedSequence.prototype.__iterator = function (type, reverse) {
        var iterator = this._iter.__iterator(ITERATE_VALUES, reverse);
        var iterations = 0;
        return new Iterator(function () {
            var step = iterator.next();
            return step.done ? step :
              iteratorValue(type, iterations++, step.value, step)
        });
    };



    createClass(ToSetSequence, SetSeq);
    function ToSetSequence(iter) {
        this._iter = iter;
        this.size = iter.size;
    }

    ToSetSequence.prototype.has = function (key) {
        return this._iter.includes(key);
    };

    ToSetSequence.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        return this._iter.__iterate(function (v) { return fn(v, v, this$0) }, reverse);
    };

    ToSetSequence.prototype.__iterator = function (type, reverse) {
        var iterator = this._iter.__iterator(ITERATE_VALUES, reverse);
        return new Iterator(function () {
            var step = iterator.next();
            return step.done ? step :
              iteratorValue(type, step.value, step.value, step);
        });
    };



    createClass(FromEntriesSequence, KeyedSeq);
    function FromEntriesSequence(entries) {
        this._iter = entries;
        this.size = entries.size;
    }

    FromEntriesSequence.prototype.entrySeq = function () {
        return this._iter.toSeq();
    };

    FromEntriesSequence.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        return this._iter.__iterate(function (entry) {
            // Check if entry exists first so array access doesn't throw for holes
            // in the parent iteration.
            if (entry) {
                validateEntry(entry);
                var indexedIterable = isIterable(entry);
                return fn(
                  indexedIterable ? entry.get(1) : entry[1],
                  indexedIterable ? entry.get(0) : entry[0],
                  this$0
                );
            }
        }, reverse);
    };

    FromEntriesSequence.prototype.__iterator = function (type, reverse) {
        var iterator = this._iter.__iterator(ITERATE_VALUES, reverse);
        return new Iterator(function () {
            while (true) {
                var step = iterator.next();
                if (step.done) {
                    return step;
                }
                var entry = step.value;
                // Check if entry exists first so array access doesn't throw for holes
                // in the parent iteration.
                if (entry) {
                    validateEntry(entry);
                    var indexedIterable = isIterable(entry);
                    return iteratorValue(
                      type,
                      indexedIterable ? entry.get(0) : entry[0],
                      indexedIterable ? entry.get(1) : entry[1],
                      step
                    );
                }
            }
        });
    };


    ToIndexedSequence.prototype.cacheResult =
    ToKeyedSequence.prototype.cacheResult =
    ToSetSequence.prototype.cacheResult =
    FromEntriesSequence.prototype.cacheResult =
      cacheResultThrough;


    function flipFactory(iterable) {
        var flipSequence = makeSequence(iterable);
        flipSequence._iter = iterable;
        flipSequence.size = iterable.size;
        flipSequence.flip = function () { return iterable };
        flipSequence.reverse = function () {
            var reversedSequence = iterable.reverse.apply(this); // super.reverse()
            reversedSequence.flip = function () { return iterable.reverse() };
            return reversedSequence;
        };
        flipSequence.has = function (key) { return iterable.includes(key) };
        flipSequence.includes = function (key) { return iterable.has(key) };
        flipSequence.cacheResult = cacheResultThrough;
        flipSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            return iterable.__iterate(function (v, k) { return fn(k, v, this$0) !== false }, reverse);
        }
        flipSequence.__iteratorUncached = function (type, reverse) {
            if (type === ITERATE_ENTRIES) {
                var iterator = iterable.__iterator(type, reverse);
                return new Iterator(function () {
                    var step = iterator.next();
                    if (!step.done) {
                        var k = step.value[0];
                        step.value[0] = step.value[1];
                        step.value[1] = k;
                    }
                    return step;
                });
            }
            return iterable.__iterator(
              type === ITERATE_VALUES ? ITERATE_KEYS : ITERATE_VALUES,
              reverse
            );
        }
        return flipSequence;
    }


    function mapFactory(iterable, mapper, context) {
        var mappedSequence = makeSequence(iterable);
        mappedSequence.size = iterable.size;
        mappedSequence.has = function (key) { return iterable.has(key) };
        mappedSequence.get = function (key, notSetValue) {
            var v = iterable.get(key, NOT_SET);
            return v === NOT_SET ?
                notSetValue :
              mapper.call(context, v, key, iterable);
        };
        mappedSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            return iterable.__iterate(
              function (v, k, c) { return fn(mapper.call(context, v, k, c), k, this$0) !== false },
              reverse
            );
        }
        mappedSequence.__iteratorUncached = function (type, reverse) {
            var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse);
            return new Iterator(function () {
                var step = iterator.next();
                if (step.done) {
                    return step;
                }
                var entry = step.value;
                var key = entry[0];
                return iteratorValue(
                  type,
                  key,
                  mapper.call(context, entry[1], key, iterable),
                  step
                );
            });
        }
        return mappedSequence;
    }


    function reverseFactory(iterable, useKeys) {
        var reversedSequence = makeSequence(iterable);
        reversedSequence._iter = iterable;
        reversedSequence.size = iterable.size;
        reversedSequence.reverse = function () { return iterable };
        if (iterable.flip) {
            reversedSequence.flip = function () {
                var flipSequence = flipFactory(iterable);
                flipSequence.reverse = function () { return iterable.flip() };
                return flipSequence;
            };
        }
        reversedSequence.get = function (key, notSetValue)
        { return iterable.get(useKeys ? key : -1 - key, notSetValue) };
        reversedSequence.has = function (key)
        { return iterable.has(useKeys ? key : -1 - key) };
        reversedSequence.includes = function (value) { return iterable.includes(value) };
        reversedSequence.cacheResult = cacheResultThrough;
        reversedSequence.__iterate = function (fn, reverse) {
            var this$0 = this;
            return iterable.__iterate(function (v, k) { return fn(v, k, this$0) }, !reverse);
        };
        reversedSequence.__iterator =
          function (type, reverse) { return iterable.__iterator(type, !reverse) };
        return reversedSequence;
    }


    function filterFactory(iterable, predicate, context, useKeys) {
        var filterSequence = makeSequence(iterable);
        if (useKeys) {
            filterSequence.has = function (key) {
                var v = iterable.get(key, NOT_SET);
                return v !== NOT_SET && !!predicate.call(context, v, key, iterable);
            };
            filterSequence.get = function (key, notSetValue) {
                var v = iterable.get(key, NOT_SET);
                return v !== NOT_SET && predicate.call(context, v, key, iterable) ?
                    v : notSetValue;
            };
        }
        filterSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            var iterations = 0;
            iterable.__iterate(function (v, k, c) {
                if (predicate.call(context, v, k, c)) {
                    iterations++;
                    return fn(v, useKeys ? k : iterations - 1, this$0);
                }
            }, reverse);
            return iterations;
        };
        filterSequence.__iteratorUncached = function (type, reverse) {
            var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse);
            var iterations = 0;
            return new Iterator(function () {
                while (true) {
                    var step = iterator.next();
                    if (step.done) {
                        return step;
                    }
                    var entry = step.value;
                    var key = entry[0];
                    var value = entry[1];
                    if (predicate.call(context, value, key, iterable)) {
                        return iteratorValue(type, useKeys ? key : iterations++, value, step);
                    }
                }
            });
        }
        return filterSequence;
    }


    function countByFactory(iterable, grouper, context) {
        var groups = Map().asMutable();
        iterable.__iterate(function (v, k) {
            groups.update(
              grouper.call(context, v, k, iterable),
              0,
              function (a) { return a + 1 }
            );
        });
        return groups.asImmutable();
    }


    function groupByFactory(iterable, grouper, context) {
        var isKeyedIter = isKeyed(iterable);
        var groups = (isOrdered(iterable) ? OrderedMap() : Map()).asMutable();
        iterable.__iterate(function (v, k) {
            groups.update(
              grouper.call(context, v, k, iterable),
              function (a) { return (a = a || [], a.push(isKeyedIter ? [k, v] : v), a) }
            );
        });
        var coerce = iterableClass(iterable);
        return groups.map(function (arr) { return reify(iterable, coerce(arr)) });
    }


    function sliceFactory(iterable, begin, end, useKeys) {
        var originalSize = iterable.size;

        // Sanitize begin & end using this shorthand for ToInt32(argument)
        // http://www.ecma-international.org/ecma-262/6.0/#sec-toint32
        if (begin !== undefined) {
            begin = begin | 0;
        }
        if (end !== undefined) {
            end = end | 0;
        }

        if (wholeSlice(begin, end, originalSize)) {
            return iterable;
        }

        var resolvedBegin = resolveBegin(begin, originalSize);
        var resolvedEnd = resolveEnd(end, originalSize);

        // begin or end will be NaN if they were provided as negative numbers and
        // this iterable's size is unknown. In that case, cache first so there is
        // a known size and these do not resolve to NaN.
        if (resolvedBegin !== resolvedBegin || resolvedEnd !== resolvedEnd) {
            return sliceFactory(iterable.toSeq().cacheResult(), begin, end, useKeys);
        }

        // Note: resolvedEnd is undefined when the original sequence's length is
        // unknown and this slice did not supply an end and should contain all
        // elements after resolvedBegin.
        // In that case, resolvedSize will be NaN and sliceSize will remain undefined.
        var resolvedSize = resolvedEnd - resolvedBegin;
        var sliceSize;
        if (resolvedSize === resolvedSize) {
            sliceSize = resolvedSize < 0 ? 0 : resolvedSize;
        }

        var sliceSeq = makeSequence(iterable);

        // If iterable.size is undefined, the size of the realized sliceSeq is
        // unknown at this point unless the number of items to slice is 0
        sliceSeq.size = sliceSize === 0 ? sliceSize : iterable.size && sliceSize || undefined;

        if (!useKeys && isSeq(iterable) && sliceSize >= 0) {
            sliceSeq.get = function (index, notSetValue) {
                index = wrapIndex(this, index);
                return index >= 0 && index < sliceSize ?
                  iterable.get(index + resolvedBegin, notSetValue) :
                  notSetValue;
            }
        }

        sliceSeq.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            if (sliceSize === 0) {
                return 0;
            }
            if (reverse) {
                return this.cacheResult().__iterate(fn, reverse);
            }
            var skipped = 0;
            var isSkipping = true;
            var iterations = 0;
            iterable.__iterate(function (v, k) {
                if (!(isSkipping && (isSkipping = skipped++ < resolvedBegin))) {
                    iterations++;
                    return fn(v, useKeys ? k : iterations - 1, this$0) !== false &&
                           iterations !== sliceSize;
                }
            });
            return iterations;
        };

        sliceSeq.__iteratorUncached = function (type, reverse) {
            if (sliceSize !== 0 && reverse) {
                return this.cacheResult().__iterator(type, reverse);
            }
            // Don't bother instantiating parent iterator if taking 0.
            var iterator = sliceSize !== 0 && iterable.__iterator(type, reverse);
            var skipped = 0;
            var iterations = 0;
            return new Iterator(function () {
                while (skipped++ < resolvedBegin) {
                    iterator.next();
                }
                if (++iterations > sliceSize) {
                    return iteratorDone();
                }
                var step = iterator.next();
                if (useKeys || type === ITERATE_VALUES) {
                    return step;
                } else if (type === ITERATE_KEYS) {
                    return iteratorValue(type, iterations - 1, undefined, step);
                } else {
                    return iteratorValue(type, iterations - 1, step.value[1], step);
                }
            });
        }

        return sliceSeq;
    }


    function takeWhileFactory(iterable, predicate, context) {
        var takeSequence = makeSequence(iterable);
        takeSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            if (reverse) {
                return this.cacheResult().__iterate(fn, reverse);
            }
            var iterations = 0;
            iterable.__iterate(function (v, k, c)
            { return predicate.call(context, v, k, c) && ++iterations && fn(v, k, this$0) }
            );
            return iterations;
        };
        takeSequence.__iteratorUncached = function (type, reverse) {
            var this$0 = this;
            if (reverse) {
                return this.cacheResult().__iterator(type, reverse);
            }
            var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse);
            var iterating = true;
            return new Iterator(function () {
                if (!iterating) {
                    return iteratorDone();
                }
                var step = iterator.next();
                if (step.done) {
                    return step;
                }
                var entry = step.value;
                var k = entry[0];
                var v = entry[1];
                if (!predicate.call(context, v, k, this$0)) {
                    iterating = false;
                    return iteratorDone();
                }
                return type === ITERATE_ENTRIES ? step :
                  iteratorValue(type, k, v, step);
            });
        };
        return takeSequence;
    }


    function skipWhileFactory(iterable, predicate, context, useKeys) {
        var skipSequence = makeSequence(iterable);
        skipSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            if (reverse) {
                return this.cacheResult().__iterate(fn, reverse);
            }
            var isSkipping = true;
            var iterations = 0;
            iterable.__iterate(function (v, k, c) {
                if (!(isSkipping && (isSkipping = predicate.call(context, v, k, c)))) {
                    iterations++;
                    return fn(v, useKeys ? k : iterations - 1, this$0);
                }
            });
            return iterations;
        };
        skipSequence.__iteratorUncached = function (type, reverse) {
            var this$0 = this;
            if (reverse) {
                return this.cacheResult().__iterator(type, reverse);
            }
            var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse);
            var skipping = true;
            var iterations = 0;
            return new Iterator(function () {
                var step, k, v;
                do {
                    step = iterator.next();
                    if (step.done) {
                        if (useKeys || type === ITERATE_VALUES) {
                            return step;
                        } else if (type === ITERATE_KEYS) {
                            return iteratorValue(type, iterations++, undefined, step);
                        } else {
                            return iteratorValue(type, iterations++, step.value[1], step);
                        }
                    }
                    var entry = step.value;
                    k = entry[0];
                    v = entry[1];
                    skipping && (skipping = predicate.call(context, v, k, this$0));
                } while (skipping);
                return type === ITERATE_ENTRIES ? step :
                  iteratorValue(type, k, v, step);
            });
        };
        return skipSequence;
    }


    function concatFactory(iterable, values) {
        var isKeyedIterable = isKeyed(iterable);
        var iters = [iterable].concat(values).map(function (v) {
            if (!isIterable(v)) {
                v = isKeyedIterable ?
                  keyedSeqFromValue(v) :
                  indexedSeqFromValue(Array.isArray(v) ? v : [v]);
            } else if (isKeyedIterable) {
                v = KeyedIterable(v);
            }
            return v;
        }).filter(function (v) { return v.size !== 0 });

        if (iters.length === 0) {
            return iterable;
        }

        if (iters.length === 1) {
            var singleton = iters[0];
            if (singleton === iterable ||
                isKeyedIterable && isKeyed(singleton) ||
                isIndexed(iterable) && isIndexed(singleton)) {
                return singleton;
            }
        }

        var concatSeq = new ArraySeq(iters);
        if (isKeyedIterable) {
            concatSeq = concatSeq.toKeyedSeq();
        } else if (!isIndexed(iterable)) {
            concatSeq = concatSeq.toSetSeq();
        }
        concatSeq = concatSeq.flatten(true);
        concatSeq.size = iters.reduce(
          function (sum, seq) {
              if (sum !== undefined) {
                  var size = seq.size;
                  if (size !== undefined) {
                      return sum + size;
                  }
              }
          },
          0
        );
        return concatSeq;
    }


    function flattenFactory(iterable, depth, useKeys) {
        var flatSequence = makeSequence(iterable);
        flatSequence.__iterateUncached = function (fn, reverse) {
            var iterations = 0;
            var stopped = false;
            function flatDeep(iter, currentDepth) {
                var this$0 = this;
                iter.__iterate(function (v, k) {
                    if ((!depth || currentDepth < depth) && isIterable(v)) {
                        flatDeep(v, currentDepth + 1);
                    } else if (fn(v, useKeys ? k : iterations++, this$0) === false) {
                        stopped = true;
                    }
                    return !stopped;
                }, reverse);
            }
            flatDeep(iterable, 0);
            return iterations;
        }
        flatSequence.__iteratorUncached = function (type, reverse) {
            var iterator = iterable.__iterator(type, reverse);
            var stack = [];
            var iterations = 0;
            return new Iterator(function () {
                while (iterator) {
                    var step = iterator.next();
                    if (step.done !== false) {
                        iterator = stack.pop();
                        continue;
                    }
                    var v = step.value;
                    if (type === ITERATE_ENTRIES) {
                        v = v[1];
                    }
                    if ((!depth || stack.length < depth) && isIterable(v)) {
                        stack.push(iterator);
                        iterator = v.__iterator(type, reverse);
                    } else {
                        return useKeys ? step : iteratorValue(type, iterations++, v, step);
                    }
                }
                return iteratorDone();
            });
        }
        return flatSequence;
    }


    function flatMapFactory(iterable, mapper, context) {
        var coerce = iterableClass(iterable);
        return iterable.toSeq().map(
          function (v, k) { return coerce(mapper.call(context, v, k, iterable)) }
        ).flatten(true);
    }


    function interposeFactory(iterable, separator) {
        var interposedSequence = makeSequence(iterable);
        interposedSequence.size = iterable.size && iterable.size * 2 - 1;
        interposedSequence.__iterateUncached = function (fn, reverse) {
            var this$0 = this;
            var iterations = 0;
            iterable.__iterate(function (v, k) {
                return (!iterations || fn(separator, iterations++, this$0) !== false) &&
                fn(v, iterations++, this$0) !== false
            },
              reverse
            );
            return iterations;
        };
        interposedSequence.__iteratorUncached = function (type, reverse) {
            var iterator = iterable.__iterator(ITERATE_VALUES, reverse);
            var iterations = 0;
            var step;
            return new Iterator(function () {
                if (!step || iterations % 2) {
                    step = iterator.next();
                    if (step.done) {
                        return step;
                    }
                }
                return iterations % 2 ?
                  iteratorValue(type, iterations++, separator) :
                  iteratorValue(type, iterations++, step.value, step);
            });
        };
        return interposedSequence;
    }


    function sortFactory(iterable, comparator, mapper) {
        if (!comparator) {
            comparator = defaultComparator;
        }
        var isKeyedIterable = isKeyed(iterable);
        var index = 0;
        var entries = iterable.toSeq().map(
          function (v, k) { return [k, v, index++, mapper ? mapper(v, k, iterable) : v] }
        ).toArray();
        entries.sort(function (a, b) { return comparator(a[3], b[3]) || a[2] - b[2] }).forEach(
          isKeyedIterable ?
          function (v, i) { entries[i].length = 2; } :
          function (v, i) { entries[i] = v[1]; }
        );
        return isKeyedIterable ? KeyedSeq(entries) :
          isIndexed(iterable) ? IndexedSeq(entries) :
          SetSeq(entries);
    }


    function maxFactory(iterable, comparator, mapper) {
        if (!comparator) {
            comparator = defaultComparator;
        }
        if (mapper) {
            var entry = iterable.toSeq()
              .map(function (v, k) { return [v, mapper(v, k, iterable)] })
              .reduce(function (a, b) { return maxCompare(comparator, a[1], b[1]) ? b : a });
            return entry && entry[0];
        } else {
            return iterable.reduce(function (a, b) { return maxCompare(comparator, a, b) ? b : a });
        }
    }

    function maxCompare(comparator, a, b) {
        var comp = comparator(b, a);
        // b is considered the new max if the comparator declares them equal, but
        // they are not equal and b is in fact a nullish value.
        return (comp === 0 && b !== a && (b === undefined || b === null || b !== b)) || comp > 0;
    }


    function zipWithFactory(keyIter, zipper, iters) {
        var zipSequence = makeSequence(keyIter);
        zipSequence.size = new ArraySeq(iters).map(function (i) { return i.size }).min();
        // Note: this a generic base implementation of __iterate in terms of
        // __iterator which may be more generically useful in the future.
        zipSequence.__iterate = function (fn, reverse) {
            /* generic:
            var iterator = this.__iterator(ITERATE_ENTRIES, reverse);
            var step;
            var iterations = 0;
            while (!(step = iterator.next()).done) {
              iterations++;
              if (fn(step.value[1], step.value[0], this) === false) {
                break;
              }
            }
            return iterations;
            */
            // indexed:
            var iterator = this.__iterator(ITERATE_VALUES, reverse);
            var step;
            var iterations = 0;
            while (!(step = iterator.next()).done) {
                if (fn(step.value, iterations++, this) === false) {
                    break;
                }
            }
            return iterations;
        };
        zipSequence.__iteratorUncached = function (type, reverse) {
            var iterators = iters.map(function (i)
            { return (i = Iterable(i), getIterator(reverse ? i.reverse() : i)) }
            );
            var iterations = 0;
            var isDone = false;
            return new Iterator(function () {
                var steps;
                if (!isDone) {
                    steps = iterators.map(function (i) { return i.next() });
                    isDone = steps.some(function (s) { return s.done });
                }
                if (isDone) {
                    return iteratorDone();
                }
                return iteratorValue(
                  type,
                  iterations++,
                  zipper.apply(null, steps.map(function (s) { return s.value }))
                );
            });
        };
        return zipSequence
    }


    // #pragma Helper Functions

    function reify(iter, seq) {
        return isSeq(iter) ? seq : iter.constructor(seq);
    }

    function validateEntry(entry) {
        if (entry !== Object(entry)) {
            throw new TypeError('Expected [K, V] tuple: ' + entry);
        }
    }

    function resolveSize(iter) {
        assertNotInfinite(iter.size);
        return ensureSize(iter);
    }

    function iterableClass(iterable) {
        return isKeyed(iterable) ? KeyedIterable :
          isIndexed(iterable) ? IndexedIterable :
          SetIterable;
    }

    function makeSequence(iterable) {
        return Object.create(
          (
            isKeyed(iterable) ? KeyedSeq :
            isIndexed(iterable) ? IndexedSeq :
            SetSeq
          ).prototype
        );
    }

    function cacheResultThrough() {
        if (this._iter.cacheResult) {
            this._iter.cacheResult();
            this.size = this._iter.size;
            return this;
        } else {
            return Seq.prototype.cacheResult.call(this);
        }
    }

    function defaultComparator(a, b) {
        return a > b ? 1 : a < b ? -1 : 0;
    }

    function forceIterator(keyPath) {
        var iter = getIterator(keyPath);
        if (!iter) {
            // Array might not be iterable in this environment, so we need a fallback
            // to our wrapped type.
            if (!isArrayLike(keyPath)) {
                throw new TypeError('Expected iterable or array-like: ' + keyPath);
            }
            iter = getIterator(Iterable(keyPath));
        }
        return iter;
    }

    createClass(Record, KeyedCollection);

    function Record(defaultValues, name) {
        var hasInitialized;

        var RecordType = function Record(values) {
            if (values instanceof RecordType) {
                return values;
            }
            if (!(this instanceof RecordType)) {
                return new RecordType(values);
            }
            if (!hasInitialized) {
                hasInitialized = true;
                var keys = Object.keys(defaultValues);
                setProps(RecordTypePrototype, keys);
                RecordTypePrototype.size = keys.length;
                RecordTypePrototype._name = name;
                RecordTypePrototype._keys = keys;
                RecordTypePrototype._defaultValues = defaultValues;
            }
            this._map = Map(values);
        };

        var RecordTypePrototype = RecordType.prototype = Object.create(RecordPrototype);
        RecordTypePrototype.constructor = RecordType;

        return RecordType;
    }

    Record.prototype.toString = function () {
        return this.__toString(recordName(this) + ' {', '}');
    };

    // @pragma Access

    Record.prototype.has = function (k) {
        return this._defaultValues.hasOwnProperty(k);
    };

    Record.prototype.get = function (k, notSetValue) {
        if (!this.has(k)) {
            return notSetValue;
        }
        var defaultVal = this._defaultValues[k];
        return this._map ? this._map.get(k, defaultVal) : defaultVal;
    };

    // @pragma Modification

    Record.prototype.clear = function () {
        if (this.__ownerID) {
            this._map && this._map.clear();
            return this;
        }
        var RecordType = this.constructor;
        return RecordType._empty || (RecordType._empty = makeRecord(this, emptyMap()));
    };

    Record.prototype.set = function (k, v) {
        if (!this.has(k)) {
            throw new Error('Cannot set unknown key "' + k + '" on ' + recordName(this));
        }
        if (this._map && !this._map.has(k)) {
            var defaultVal = this._defaultValues[k];
            if (v === defaultVal) {
                return this;
            }
        }
        var newMap = this._map && this._map.set(k, v);
        if (this.__ownerID || newMap === this._map) {
            return this;
        }
        return makeRecord(this, newMap);
    };

    Record.prototype.remove = function (k) {
        if (!this.has(k)) {
            return this;
        }
        var newMap = this._map && this._map.remove(k);
        if (this.__ownerID || newMap === this._map) {
            return this;
        }
        return makeRecord(this, newMap);
    };

    Record.prototype.wasAltered = function () {
        return this._map.wasAltered();
    };

    Record.prototype.__iterator = function (type, reverse) {
        var this$0 = this;
        return KeyedIterable(this._defaultValues).map(function (_, k) { return this$0.get(k) }).__iterator(type, reverse);
    };

    Record.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        return KeyedIterable(this._defaultValues).map(function (_, k) { return this$0.get(k) }).__iterate(fn, reverse);
    };

    Record.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        var newMap = this._map && this._map.__ensureOwner(ownerID);
        if (!ownerID) {
            this.__ownerID = ownerID;
            this._map = newMap;
            return this;
        }
        return makeRecord(this, newMap, ownerID);
    };


    var RecordPrototype = Record.prototype;
    RecordPrototype[DELETE] = RecordPrototype.remove;
    RecordPrototype.deleteIn =
    RecordPrototype.removeIn = MapPrototype.removeIn;
    RecordPrototype.merge = MapPrototype.merge;
    RecordPrototype.mergeWith = MapPrototype.mergeWith;
    RecordPrototype.mergeIn = MapPrototype.mergeIn;
    RecordPrototype.mergeDeep = MapPrototype.mergeDeep;
    RecordPrototype.mergeDeepWith = MapPrototype.mergeDeepWith;
    RecordPrototype.mergeDeepIn = MapPrototype.mergeDeepIn;
    RecordPrototype.setIn = MapPrototype.setIn;
    RecordPrototype.update = MapPrototype.update;
    RecordPrototype.updateIn = MapPrototype.updateIn;
    RecordPrototype.withMutations = MapPrototype.withMutations;
    RecordPrototype.asMutable = MapPrototype.asMutable;
    RecordPrototype.asImmutable = MapPrototype.asImmutable;


    function makeRecord(likeRecord, map, ownerID) {
        var record = Object.create(Object.getPrototypeOf(likeRecord));
        record._map = map;
        record.__ownerID = ownerID;
        return record;
    }

    function recordName(record) {
        return record._name || record.constructor.name || 'Record';
    }

    function setProps(prototype, names) {
        try {
            names.forEach(setProp.bind(undefined, prototype));
        } catch (error) {
            // Object.defineProperty failed. Probably IE8.
        }
    }

    function setProp(prototype, name) {
        Object.defineProperty(prototype, name, {
            get: function () {
                return this.get(name);
            },
            set: function (value) {
                invariant(this.__ownerID, 'Cannot set on an immutable record.');
                this.set(name, value);
            }
        });
    }

    createClass(Set, SetCollection);

    // @pragma Construction

    function Set(value) {
        return value === null || value === undefined ? emptySet() :
          isSet(value) && !isOrdered(value) ? value :
          emptySet().withMutations(function (set) {
              var iter = SetIterable(value);
              assertNotInfinite(iter.size);
              iter.forEach(function (v) { return set.add(v) });
          });
    }

    Set.of = function (/*...values*/) {
        return this(arguments);
    };

    Set.fromKeys = function (value) {
        return this(KeyedIterable(value).keySeq());
    };

    Set.prototype.toString = function () {
        return this.__toString('Set {', '}');
    };

    // @pragma Access

    Set.prototype.has = function (value) {
        return this._map.has(value);
    };

    // @pragma Modification

    Set.prototype.add = function (value) {
        return updateSet(this, this._map.set(value, true));
    };

    Set.prototype.remove = function (value) {
        return updateSet(this, this._map.remove(value));
    };

    Set.prototype.clear = function () {
        return updateSet(this, this._map.clear());
    };

    // @pragma Composition

    Set.prototype.union = function () {
        var iters = SLICE$0.call(arguments, 0);
        iters = iters.filter(function (x) { return x.size !== 0 });
        if (iters.length === 0) {
            return this;
        }
        if (this.size === 0 && !this.__ownerID && iters.length === 1) {
            return this.constructor(iters[0]);
        }
        return this.withMutations(function (set) {
            for (var ii = 0; ii < iters.length; ii++) {
                SetIterable(iters[ii]).forEach(function (value) { return set.add(value) });
            }
        });
    };

    Set.prototype.intersect = function () {
        var iters = SLICE$0.call(arguments, 0);
        if (iters.length === 0) {
            return this;
        }
        iters = iters.map(function (iter) { return SetIterable(iter) });
        var originalSet = this;
        return this.withMutations(function (set) {
            originalSet.forEach(function (value) {
                if (!iters.every(function (iter) { return iter.includes(value) })) {
                    set.remove(value);
                }
            });
        });
    };

    Set.prototype.subtract = function () {
        var iters = SLICE$0.call(arguments, 0);
        if (iters.length === 0) {
            return this;
        }
        iters = iters.map(function (iter) { return SetIterable(iter) });
        var originalSet = this;
        return this.withMutations(function (set) {
            originalSet.forEach(function (value) {
                if (iters.some(function (iter) { return iter.includes(value) })) {
                    set.remove(value);
                }
            });
        });
    };

    Set.prototype.merge = function () {
        return this.union.apply(this, arguments);
    };

    Set.prototype.mergeWith = function (merger) {
        var iters = SLICE$0.call(arguments, 1);
        return this.union.apply(this, iters);
    };

    Set.prototype.sort = function (comparator) {
        // Late binding
        return OrderedSet(sortFactory(this, comparator));
    };

    Set.prototype.sortBy = function (mapper, comparator) {
        // Late binding
        return OrderedSet(sortFactory(this, comparator, mapper));
    };

    Set.prototype.wasAltered = function () {
        return this._map.wasAltered();
    };

    Set.prototype.__iterate = function (fn, reverse) {
        var this$0 = this;
        return this._map.__iterate(function (_, k) { return fn(k, k, this$0) }, reverse);
    };

    Set.prototype.__iterator = function (type, reverse) {
        return this._map.map(function (_, k) { return k }).__iterator(type, reverse);
    };

    Set.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        var newMap = this._map.__ensureOwner(ownerID);
        if (!ownerID) {
            this.__ownerID = ownerID;
            this._map = newMap;
            return this;
        }
        return this.__make(newMap, ownerID);
    };


    function isSet(maybeSet) {
        return !!(maybeSet && maybeSet[IS_SET_SENTINEL]);
    }

    Set.isSet = isSet;

    var IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@';

    var SetPrototype = Set.prototype;
    SetPrototype[IS_SET_SENTINEL] = true;
    SetPrototype[DELETE] = SetPrototype.remove;
    SetPrototype.mergeDeep = SetPrototype.merge;
    SetPrototype.mergeDeepWith = SetPrototype.mergeWith;
    SetPrototype.withMutations = MapPrototype.withMutations;
    SetPrototype.asMutable = MapPrototype.asMutable;
    SetPrototype.asImmutable = MapPrototype.asImmutable;

    SetPrototype.__empty = emptySet;
    SetPrototype.__make = makeSet;

    function updateSet(set, newMap) {
        if (set.__ownerID) {
            set.size = newMap.size;
            set._map = newMap;
            return set;
        }
        return newMap === set._map ? set :
          newMap.size === 0 ? set.__empty() :
          set.__make(newMap);
    }

    function makeSet(map, ownerID) {
        var set = Object.create(SetPrototype);
        set.size = map ? map.size : 0;
        set._map = map;
        set.__ownerID = ownerID;
        return set;
    }

    var EMPTY_SET;
    function emptySet() {
        return EMPTY_SET || (EMPTY_SET = makeSet(emptyMap()));
    }

    createClass(OrderedSet, Set);

    // @pragma Construction

    function OrderedSet(value) {
        return value === null || value === undefined ? emptyOrderedSet() :
          isOrderedSet(value) ? value :
          emptyOrderedSet().withMutations(function (set) {
              var iter = SetIterable(value);
              assertNotInfinite(iter.size);
              iter.forEach(function (v) { return set.add(v) });
          });
    }

    OrderedSet.of = function (/*...values*/) {
        return this(arguments);
    };

    OrderedSet.fromKeys = function (value) {
        return this(KeyedIterable(value).keySeq());
    };

    OrderedSet.prototype.toString = function () {
        return this.__toString('OrderedSet {', '}');
    };


    function isOrderedSet(maybeOrderedSet) {
        return isSet(maybeOrderedSet) && isOrdered(maybeOrderedSet);
    }

    OrderedSet.isOrderedSet = isOrderedSet;

    var OrderedSetPrototype = OrderedSet.prototype;
    OrderedSetPrototype[IS_ORDERED_SENTINEL] = true;

    OrderedSetPrototype.__empty = emptyOrderedSet;
    OrderedSetPrototype.__make = makeOrderedSet;

    function makeOrderedSet(map, ownerID) {
        var set = Object.create(OrderedSetPrototype);
        set.size = map ? map.size : 0;
        set._map = map;
        set.__ownerID = ownerID;
        return set;
    }

    var EMPTY_ORDERED_SET;
    function emptyOrderedSet() {
        return EMPTY_ORDERED_SET || (EMPTY_ORDERED_SET = makeOrderedSet(emptyOrderedMap()));
    }

    createClass(Stack, IndexedCollection);

    // @pragma Construction

    function Stack(value) {
        return value === null || value === undefined ? emptyStack() :
          isStack(value) ? value :
          emptyStack().unshiftAll(value);
    }

    Stack.of = function (/*...values*/) {
        return this(arguments);
    };

    Stack.prototype.toString = function () {
        return this.__toString('Stack [', ']');
    };

    // @pragma Access

    Stack.prototype.get = function (index, notSetValue) {
        var head = this._head;
        index = wrapIndex(this, index);
        while (head && index--) {
            head = head.next;
        }
        return head ? head.value : notSetValue;
    };

    Stack.prototype.peek = function () {
        return this._head && this._head.value;
    };

    // @pragma Modification

    Stack.prototype.push = function (/*...values*/) {
        if (arguments.length === 0) {
            return this;
        }
        var newSize = this.size + arguments.length;
        var head = this._head;
        for (var ii = arguments.length - 1; ii >= 0; ii--) {
            head = {
                value: arguments[ii],
                next: head
            };
        }
        if (this.__ownerID) {
            this.size = newSize;
            this._head = head;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return makeStack(newSize, head);
    };

    Stack.prototype.pushAll = function (iter) {
        iter = IndexedIterable(iter);
        if (iter.size === 0) {
            return this;
        }
        assertNotInfinite(iter.size);
        var newSize = this.size;
        var head = this._head;
        iter.reverse().forEach(function (value) {
            newSize++;
            head = {
                value: value,
                next: head
            };
        });
        if (this.__ownerID) {
            this.size = newSize;
            this._head = head;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return makeStack(newSize, head);
    };

    Stack.prototype.pop = function () {
        return this.slice(1);
    };

    Stack.prototype.unshift = function (/*...values*/) {
        return this.push.apply(this, arguments);
    };

    Stack.prototype.unshiftAll = function (iter) {
        return this.pushAll(iter);
    };

    Stack.prototype.shift = function () {
        return this.pop.apply(this, arguments);
    };

    Stack.prototype.clear = function () {
        if (this.size === 0) {
            return this;
        }
        if (this.__ownerID) {
            this.size = 0;
            this._head = undefined;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return emptyStack();
    };

    Stack.prototype.slice = function (begin, end) {
        if (wholeSlice(begin, end, this.size)) {
            return this;
        }
        var resolvedBegin = resolveBegin(begin, this.size);
        var resolvedEnd = resolveEnd(end, this.size);
        if (resolvedEnd !== this.size) {
            // super.slice(begin, end);
            return IndexedCollection.prototype.slice.call(this, begin, end);
        }
        var newSize = this.size - resolvedBegin;
        var head = this._head;
        while (resolvedBegin--) {
            head = head.next;
        }
        if (this.__ownerID) {
            this.size = newSize;
            this._head = head;
            this.__hash = undefined;
            this.__altered = true;
            return this;
        }
        return makeStack(newSize, head);
    };

    // @pragma Mutability

    Stack.prototype.__ensureOwner = function (ownerID) {
        if (ownerID === this.__ownerID) {
            return this;
        }
        if (!ownerID) {
            this.__ownerID = ownerID;
            this.__altered = false;
            return this;
        }
        return makeStack(this.size, this._head, ownerID, this.__hash);
    };

    // @pragma Iteration

    Stack.prototype.__iterate = function (fn, reverse) {
        if (reverse) {
            return this.reverse().__iterate(fn);
        }
        var iterations = 0;
        var node = this._head;
        while (node) {
            if (fn(node.value, iterations++, this) === false) {
                break;
            }
            node = node.next;
        }
        return iterations;
    };

    Stack.prototype.__iterator = function (type, reverse) {
        if (reverse) {
            return this.reverse().__iterator(type);
        }
        var iterations = 0;
        var node = this._head;
        return new Iterator(function () {
            if (node) {
                var value = node.value;
                node = node.next;
                return iteratorValue(type, iterations++, value);
            }
            return iteratorDone();
        });
    };


    function isStack(maybeStack) {
        return !!(maybeStack && maybeStack[IS_STACK_SENTINEL]);
    }

    Stack.isStack = isStack;

    var IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@';

    var StackPrototype = Stack.prototype;
    StackPrototype[IS_STACK_SENTINEL] = true;
    StackPrototype.withMutations = MapPrototype.withMutations;
    StackPrototype.asMutable = MapPrototype.asMutable;
    StackPrototype.asImmutable = MapPrototype.asImmutable;
    StackPrototype.wasAltered = MapPrototype.wasAltered;


    function makeStack(size, head, ownerID, hash) {
        var map = Object.create(StackPrototype);
        map.size = size;
        map._head = head;
        map.__ownerID = ownerID;
        map.__hash = hash;
        map.__altered = false;
        return map;
    }

    var EMPTY_STACK;
    function emptyStack() {
        return EMPTY_STACK || (EMPTY_STACK = makeStack(0));
    }

    /**
     * Contributes additional methods to a constructor
     */
    function mixin(ctor, methods) {
        var keyCopier = function (key) { ctor.prototype[key] = methods[key]; };
        Object.keys(methods).forEach(keyCopier);
        Object.getOwnPropertySymbols &&
          Object.getOwnPropertySymbols(methods).forEach(keyCopier);
        return ctor;
    }

    Iterable.Iterator = Iterator;

    mixin(Iterable, {

        // ### Conversion to other types

        toArray: function () {
            assertNotInfinite(this.size);
            var array = new Array(this.size || 0);
            this.valueSeq().__iterate(function (v, i) { array[i] = v; });
            return array;
        },

        toIndexedSeq: function () {
            return new ToIndexedSequence(this);
        },

        toJS: function () {
            return this.toSeq().map(
              function (value) { return value && typeof value.toJS === 'function' ? value.toJS() : value }
            ).__toJS();
        },

        toJSON: function () {
            return this.toSeq().map(
              function (value) { return value && typeof value.toJSON === 'function' ? value.toJSON() : value }
            ).__toJS();
        },

        toKeyedSeq: function () {
            return new ToKeyedSequence(this, true);
        },

        toMap: function () {
            // Use Late Binding here to solve the circular dependency.
            return Map(this.toKeyedSeq());
        },

        toObject: function () {
            assertNotInfinite(this.size);
            var object = {};
            this.__iterate(function (v, k) { object[k] = v; });
            return object;
        },

        toOrderedMap: function () {
            // Use Late Binding here to solve the circular dependency.
            return OrderedMap(this.toKeyedSeq());
        },

        toOrderedSet: function () {
            // Use Late Binding here to solve the circular dependency.
            return OrderedSet(isKeyed(this) ? this.valueSeq() : this);
        },

        toSet: function () {
            // Use Late Binding here to solve the circular dependency.
            return Set(isKeyed(this) ? this.valueSeq() : this);
        },

        toSetSeq: function () {
            return new ToSetSequence(this);
        },

        toSeq: function () {
            return isIndexed(this) ? this.toIndexedSeq() :
              isKeyed(this) ? this.toKeyedSeq() :
              this.toSetSeq();
        },

        toStack: function () {
            // Use Late Binding here to solve the circular dependency.
            return Stack(isKeyed(this) ? this.valueSeq() : this);
        },

        toList: function () {
            // Use Late Binding here to solve the circular dependency.
            return List(isKeyed(this) ? this.valueSeq() : this);
        },


        // ### Common JavaScript methods and properties

        toString: function () {
            return '[Iterable]';
        },

        __toString: function (head, tail) {
            if (this.size === 0) {
                return head + tail;
            }
            return head + ' ' + this.toSeq().map(this.__toStringMapper).join(', ') + ' ' + tail;
        },


        // ### ES6 Collection methods (ES6 Array and Map)

        concat: function () {
            var values = SLICE$0.call(arguments, 0);
            return reify(this, concatFactory(this, values));
        },

        includes: function (searchValue) {
            return this.some(function (value) { return is(value, searchValue) });
        },

        entries: function () {
            return this.__iterator(ITERATE_ENTRIES);
        },

        every: function (predicate, context) {
            assertNotInfinite(this.size);
            var returnValue = true;
            this.__iterate(function (v, k, c) {
                if (!predicate.call(context, v, k, c)) {
                    returnValue = false;
                    return false;
                }
            });
            return returnValue;
        },

        filter: function (predicate, context) {
            return reify(this, filterFactory(this, predicate, context, true));
        },

        find: function (predicate, context, notSetValue) {
            var entry = this.findEntry(predicate, context);
            return entry ? entry[1] : notSetValue;
        },

        findEntry: function (predicate, context) {
            var found;
            this.__iterate(function (v, k, c) {
                if (predicate.call(context, v, k, c)) {
                    found = [k, v];
                    return false;
                }
            });
            return found;
        },

        findLastEntry: function (predicate, context) {
            return this.toSeq().reverse().findEntry(predicate, context);
        },

        forEach: function (sideEffect, context) {
            assertNotInfinite(this.size);
            return this.__iterate(context ? sideEffect.bind(context) : sideEffect);
        },

        join: function (separator) {
            assertNotInfinite(this.size);
            separator = separator !== undefined ? '' + separator : ',';
            var joined = '';
            var isFirst = true;
            this.__iterate(function (v) {
                isFirst ? (isFirst = false) : (joined += separator);
                joined += v !== null && v !== undefined ? v.toString() : '';
            });
            return joined;
        },

        keys: function () {
            return this.__iterator(ITERATE_KEYS);
        },

        map: function (mapper, context) {
            return reify(this, mapFactory(this, mapper, context));
        },

        reduce: function (reducer, initialReduction, context) {
            assertNotInfinite(this.size);
            var reduction;
            var useFirst;
            if (arguments.length < 2) {
                useFirst = true;
            } else {
                reduction = initialReduction;
            }
            this.__iterate(function (v, k, c) {
                if (useFirst) {
                    useFirst = false;
                    reduction = v;
                } else {
                    reduction = reducer.call(context, reduction, v, k, c);
                }
            });
            return reduction;
        },

        reduceRight: function (reducer, initialReduction, context) {
            var reversed = this.toKeyedSeq().reverse();
            return reversed.reduce.apply(reversed, arguments);
        },

        reverse: function () {
            return reify(this, reverseFactory(this, true));
        },

        slice: function (begin, end) {
            return reify(this, sliceFactory(this, begin, end, true));
        },

        some: function (predicate, context) {
            return !this.every(not(predicate), context);
        },

        sort: function (comparator) {
            return reify(this, sortFactory(this, comparator));
        },

        values: function () {
            return this.__iterator(ITERATE_VALUES);
        },


        // ### More sequential methods

        butLast: function () {
            return this.slice(0, -1);
        },

        isEmpty: function () {
            return this.size !== undefined ? this.size === 0 : !this.some(function () { return true });
        },

        count: function (predicate, context) {
            return ensureSize(
              predicate ? this.toSeq().filter(predicate, context) : this
            );
        },

        countBy: function (grouper, context) {
            return countByFactory(this, grouper, context);
        },

        equals: function (other) {
            return deepEqual(this, other);
        },

        entrySeq: function () {
            var iterable = this;
            if (iterable._cache) {
                // We cache as an entries array, so we can just return the cache!
                return new ArraySeq(iterable._cache);
            }
            var entriesSequence = iterable.toSeq().map(entryMapper).toIndexedSeq();
            entriesSequence.fromEntrySeq = function () { return iterable.toSeq() };
            return entriesSequence;
        },

        filterNot: function (predicate, context) {
            return this.filter(not(predicate), context);
        },

        findLast: function (predicate, context, notSetValue) {
            return this.toKeyedSeq().reverse().find(predicate, context, notSetValue);
        },

        first: function () {
            return this.find(returnTrue);
        },

        flatMap: function (mapper, context) {
            return reify(this, flatMapFactory(this, mapper, context));
        },

        flatten: function (depth) {
            return reify(this, flattenFactory(this, depth, true));
        },

        fromEntrySeq: function () {
            return new FromEntriesSequence(this);
        },

        get: function (searchKey, notSetValue) {
            return this.find(function (_, key) { return is(key, searchKey) }, undefined, notSetValue);
        },

        getIn: function (searchKeyPath, notSetValue) {
            var nested = this;
            // Note: in an ES6 environment, we would prefer:
            // for (var key of searchKeyPath) {
            var iter = forceIterator(searchKeyPath);
            var step;
            while (!(step = iter.next()).done) {
                var key = step.value;
                nested = nested && nested.get ? nested.get(key, NOT_SET) : NOT_SET;
                if (nested === NOT_SET) {
                    return notSetValue;
                }
            }
            return nested;
        },

        groupBy: function (grouper, context) {
            return groupByFactory(this, grouper, context);
        },

        has: function (searchKey) {
            return this.get(searchKey, NOT_SET) !== NOT_SET;
        },

        hasIn: function (searchKeyPath) {
            return this.getIn(searchKeyPath, NOT_SET) !== NOT_SET;
        },

        isSubset: function (iter) {
            iter = typeof iter.includes === 'function' ? iter : Iterable(iter);
            return this.every(function (value) { return iter.includes(value) });
        },

        isSuperset: function (iter) {
            iter = typeof iter.isSubset === 'function' ? iter : Iterable(iter);
            return iter.isSubset(this);
        },

        keySeq: function () {
            return this.toSeq().map(keyMapper).toIndexedSeq();
        },

        last: function () {
            return this.toSeq().reverse().first();
        },

        max: function (comparator) {
            return maxFactory(this, comparator);
        },

        maxBy: function (mapper, comparator) {
            return maxFactory(this, comparator, mapper);
        },

        min: function (comparator) {
            return maxFactory(this, comparator ? neg(comparator) : defaultNegComparator);
        },

        minBy: function (mapper, comparator) {
            return maxFactory(this, comparator ? neg(comparator) : defaultNegComparator, mapper);
        },

        rest: function () {
            return this.slice(1);
        },

        skip: function (amount) {
            return this.slice(Math.max(0, amount));
        },

        skipLast: function (amount) {
            return reify(this, this.toSeq().reverse().skip(amount).reverse());
        },

        skipWhile: function (predicate, context) {
            return reify(this, skipWhileFactory(this, predicate, context, true));
        },

        skipUntil: function (predicate, context) {
            return this.skipWhile(not(predicate), context);
        },

        sortBy: function (mapper, comparator) {
            return reify(this, sortFactory(this, comparator, mapper));
        },

        take: function (amount) {
            return this.slice(0, Math.max(0, amount));
        },

        takeLast: function (amount) {
            return reify(this, this.toSeq().reverse().take(amount).reverse());
        },

        takeWhile: function (predicate, context) {
            return reify(this, takeWhileFactory(this, predicate, context));
        },

        takeUntil: function (predicate, context) {
            return this.takeWhile(not(predicate), context);
        },

        valueSeq: function () {
            return this.toIndexedSeq();
        },


        // ### Hashable Object

        hashCode: function () {
            return this.__hash || (this.__hash = hashIterable(this));
        }


        // ### Internal

        // abstract __iterate(fn, reverse)

        // abstract __iterator(type, reverse)
    });

    // var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
    // var IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';
    // var IS_INDEXED_SENTINEL = '@@__IMMUTABLE_INDEXED__@@';
    // var IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';

    var IterablePrototype = Iterable.prototype;
    IterablePrototype[IS_ITERABLE_SENTINEL] = true;
    IterablePrototype[ITERATOR_SYMBOL] = IterablePrototype.values;
    IterablePrototype.__toJS = IterablePrototype.toArray;
    IterablePrototype.__toStringMapper = quoteString;
    IterablePrototype.inspect =
    IterablePrototype.toSource = function () { return this.toString(); };
    IterablePrototype.chain = IterablePrototype.flatMap;
    IterablePrototype.contains = IterablePrototype.includes;

    // Temporary warning about using length
    (function () {
        try {
            Object.defineProperty(IterablePrototype, 'length', {
                get: function () {
                    if (!Iterable.noLengthWarning) {
                        var stack;
                        try {
                            throw new Error();
                        } catch (error) {
                            stack = error.stack;
                        }
                        if (stack.indexOf('_wrapObject') === -1) {
                            console && console.warn && console.warn(
                              'iterable.length has been deprecated, ' +
                              'use iterable.size or iterable.count(). ' +
                              'This warning will become a silent error in a future version. ' +
                              stack
                            );
                            return this.size;
                        }
                    }
                }
            });
        } catch (e) { }
    })();



    mixin(KeyedIterable, {

        // ### More sequential methods

        flip: function () {
            return reify(this, flipFactory(this));
        },

        findKey: function (predicate, context) {
            var entry = this.findEntry(predicate, context);
            return entry && entry[0];
        },

        findLastKey: function (predicate, context) {
            return this.toSeq().reverse().findKey(predicate, context);
        },

        keyOf: function (searchValue) {
            return this.findKey(function (value) { return is(value, searchValue) });
        },

        lastKeyOf: function (searchValue) {
            return this.findLastKey(function (value) { return is(value, searchValue) });
        },

        mapEntries: function (mapper, context) {
            var this$0 = this;
            var iterations = 0;
            return reify(this,
              this.toSeq().map(
                function (v, k) { return mapper.call(context, [k, v], iterations++, this$0) }
              ).fromEntrySeq()
            );
        },

        mapKeys: function (mapper, context) {
            var this$0 = this;
            return reify(this,
              this.toSeq().flip().map(
                function (k, v) { return mapper.call(context, k, v, this$0) }
              ).flip()
            );
        }

    });

    var KeyedIterablePrototype = KeyedIterable.prototype;
    KeyedIterablePrototype[IS_KEYED_SENTINEL] = true;
    KeyedIterablePrototype[ITERATOR_SYMBOL] = IterablePrototype.entries;
    KeyedIterablePrototype.__toJS = IterablePrototype.toObject;
    KeyedIterablePrototype.__toStringMapper = function (v, k) { return JSON.stringify(k) + ': ' + quoteString(v) };



    mixin(IndexedIterable, {

        // ### Conversion to other types

        toKeyedSeq: function () {
            return new ToKeyedSequence(this, false);
        },


        // ### ES6 Collection methods (ES6 Array and Map)

        filter: function (predicate, context) {
            return reify(this, filterFactory(this, predicate, context, false));
        },

        findIndex: function (predicate, context) {
            var entry = this.findEntry(predicate, context);
            return entry ? entry[0] : -1;
        },

        indexOf: function (searchValue) {
            var key = this.toKeyedSeq().keyOf(searchValue);
            return key === undefined ? -1 : key;
        },

        lastIndexOf: function (searchValue) {
            var key = this.toKeyedSeq().reverse().keyOf(searchValue);
            return key === undefined ? -1 : key;
        },

        reverse: function () {
            return reify(this, reverseFactory(this, false));
        },

        slice: function (begin, end) {
            return reify(this, sliceFactory(this, begin, end, false));
        },

        splice: function (index, removeNum /*, ...values*/) {
            var numArgs = arguments.length;
            removeNum = Math.max(removeNum | 0, 0);
            if (numArgs === 0 || (numArgs === 2 && !removeNum)) {
                return this;
            }
            // If index is negative, it should resolve relative to the size of the
            // collection. However size may be expensive to compute if not cached, so
            // only call count() if the number is in fact negative.
            index = resolveBegin(index, index < 0 ? this.count() : this.size);
            var spliced = this.slice(0, index);
            return reify(
              this,
              numArgs === 1 ?
                spliced :
                spliced.concat(arrCopy(arguments, 2), this.slice(index + removeNum))
            );
        },


        // ### More collection methods

        findLastIndex: function (predicate, context) {
            var key = this.toKeyedSeq().findLastKey(predicate, context);
            return key === undefined ? -1 : key;
        },

        first: function () {
            return this.get(0);
        },

        flatten: function (depth) {
            return reify(this, flattenFactory(this, depth, false));
        },

        get: function (index, notSetValue) {
            index = wrapIndex(this, index);
            return (index < 0 || (this.size === Infinity ||
                (this.size !== undefined && index > this.size))) ?
                notSetValue :
              this.find(function (_, key) { return key === index }, undefined, notSetValue);
        },

        has: function (index) {
            index = wrapIndex(this, index);
            return index >= 0 && (this.size !== undefined ?
              this.size === Infinity || index < this.size :
              this.indexOf(index) !== -1
            );
        },

        interpose: function (separator) {
            return reify(this, interposeFactory(this, separator));
        },

        interleave: function (/*...iterables*/) {
            var iterables = [this].concat(arrCopy(arguments));
            var zipped = zipWithFactory(this.toSeq(), IndexedSeq.of, iterables);
            var interleaved = zipped.flatten(true);
            if (zipped.size) {
                interleaved.size = zipped.size * iterables.length;
            }
            return reify(this, interleaved);
        },

        last: function () {
            return this.get(-1);
        },

        skipWhile: function (predicate, context) {
            return reify(this, skipWhileFactory(this, predicate, context, false));
        },

        zip: function (/*, ...iterables */) {
            var iterables = [this].concat(arrCopy(arguments));
            return reify(this, zipWithFactory(this, defaultZipper, iterables));
        },

        zipWith: function (zipper/*, ...iterables */) {
            var iterables = arrCopy(arguments);
            iterables[0] = this;
            return reify(this, zipWithFactory(this, zipper, iterables));
        }

    });

    IndexedIterable.prototype[IS_INDEXED_SENTINEL] = true;
    IndexedIterable.prototype[IS_ORDERED_SENTINEL] = true;



    mixin(SetIterable, {

        // ### ES6 Collection methods (ES6 Array and Map)

        get: function (value, notSetValue) {
            return this.has(value) ? value : notSetValue;
        },

        includes: function (value) {
            return this.has(value);
        },


        // ### More sequential methods

        keySeq: function () {
            return this.valueSeq();
        }

    });

    SetIterable.prototype.has = IterablePrototype.includes;
    SetIterable.prototype.contains = SetIterable.prototype.includes;


    // Mixin subclasses

    mixin(KeyedSeq, KeyedIterable.prototype);
    mixin(IndexedSeq, IndexedIterable.prototype);
    mixin(SetSeq, SetIterable.prototype);

    mixin(KeyedCollection, KeyedIterable.prototype);
    mixin(IndexedCollection, IndexedIterable.prototype);
    mixin(SetCollection, SetIterable.prototype);


    // #pragma Helper functions

    function keyMapper(v, k) {
        return k;
    }

    function entryMapper(v, k) {
        return [k, v];
    }

    function not(predicate) {
        return function () {
            return !predicate.apply(this, arguments);
        }
    }

    function neg(predicate) {
        return function () {
            return -predicate.apply(this, arguments);
        }
    }

    function quoteString(value) {
        return typeof value === 'string' ? JSON.stringify(value) : value;
    }

    function defaultZipper() {
        return arrCopy(arguments);
    }

    function defaultNegComparator(a, b) {
        return a < b ? 1 : a > b ? -1 : 0;
    }

    function hashIterable(iterable) {
        if (iterable.size === Infinity) {
            return 0;
        }
        var ordered = isOrdered(iterable);
        var keyed = isKeyed(iterable);
        var h = ordered ? 1 : 0;
        var size = iterable.__iterate(
          keyed ?
            ordered ?
              function (v, k) { h = 31 * h + hashMerge(hash(v), hash(k)) | 0; } :
              function (v, k) { h = h + hashMerge(hash(v), hash(k)) | 0; } :
            ordered ?
              function (v) { h = 31 * h + hash(v) | 0; } :
              function (v) { h = h + hash(v) | 0; }
        );
        return murmurHashOfSize(size, h);
    }

    function murmurHashOfSize(size, h) {
        h = imul(h, 0xCC9E2D51);
        h = imul(h << 15 | h >>> -15, 0x1B873593);
        h = imul(h << 13 | h >>> -13, 5);
        h = (h + 0xE6546B64 | 0) ^ size;
        h = imul(h ^ h >>> 16, 0x85EBCA6B);
        h = imul(h ^ h >>> 13, 0xC2B2AE35);
        h = smi(h ^ h >>> 16);
        return h;
    }

    function hashMerge(a, b) {
        return a ^ b + 0x9E3779B9 + (a << 6) + (a >> 2) | 0; // int
    }

    var Immutable = {

        Iterable: Iterable,

        Seq: Seq,
        Collection: Collection,
        Map: Map,
        OrderedMap: OrderedMap,
        List: List,
        Stack: Stack,
        Set: Set,
        OrderedSet: OrderedSet,

        Record: Record,
        Range: Range,
        Repeat: Repeat,

        is: is,
        fromJS: fromJS

    };

    return Immutable;

}));
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */

var __LiteMolZlib = {};
(function () {
    'use strict'; function q(b) { throw b; } var t = void 0, u = !0, aa = this; function A(b, a) { var c = b.split("."), d = aa; !(c[0] in d) && d.execScript && d.execScript("var " + c[0]); for (var e; c.length && (e = c.shift()) ;) !c.length && a !== t ? d[e] = a : d = d[e] ? d[e] : d[e] = {} }; var B = "undefined" !== typeof Uint8Array && "undefined" !== typeof Uint16Array && "undefined" !== typeof Uint32Array && "undefined" !== typeof DataView; function F(b, a) { this.index = "number" === typeof a ? a : 0; this.m = 0; this.buffer = b instanceof (B ? Uint8Array : Array) ? b : new (B ? Uint8Array : Array)(32768); 2 * this.buffer.length <= this.index && q(Error("invalid index")); this.buffer.length <= this.index && this.f() } F.prototype.f = function () { var b = this.buffer, a, c = b.length, d = new (B ? Uint8Array : Array)(c << 1); if (B) d.set(b); else for (a = 0; a < c; ++a) d[a] = b[a]; return this.buffer = d };
    F.prototype.d = function (b, a, c) { var d = this.buffer, e = this.index, f = this.m, g = d[e], k; c && 1 < a && (b = 8 < a ? (H[b & 255] << 24 | H[b >>> 8 & 255] << 16 | H[b >>> 16 & 255] << 8 | H[b >>> 24 & 255]) >> 32 - a : H[b] >> 8 - a); if (8 > a + f) g = g << a | b, f += a; else for (k = 0; k < a; ++k) g = g << 1 | b >> a - k - 1 & 1, 8 === ++f && (f = 0, d[e++] = H[g], g = 0, e === d.length && (d = this.f())); d[e] = g; this.buffer = d; this.m = f; this.index = e }; F.prototype.finish = function () { var b = this.buffer, a = this.index, c; 0 < this.m && (b[a] <<= 8 - this.m, b[a] = H[b[a]], a++); B ? c = b.subarray(0, a) : (b.length = a, c = b); return c };
    var ba = new (B ? Uint8Array : Array)(256), ca; for (ca = 0; 256 > ca; ++ca) { for (var K = ca, da = K, ea = 7, K = K >>> 1; K; K >>>= 1) da <<= 1, da |= K & 1, --ea; ba[ca] = (da << ea & 255) >>> 0 } var H = ba; function ja(b, a, c) { var d, e = "number" === typeof a ? a : a = 0, f = "number" === typeof c ? c : b.length; d = -1; for (e = f & 7; e--; ++a) d = d >>> 8 ^ O[(d ^ b[a]) & 255]; for (e = f >> 3; e--; a += 8) d = d >>> 8 ^ O[(d ^ b[a]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 1]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 2]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 3]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 4]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 5]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 6]) & 255], d = d >>> 8 ^ O[(d ^ b[a + 7]) & 255]; return (d ^ 4294967295) >>> 0 }
    var ka = [0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759,
    2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977,
    2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755,
    2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956,
    3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270,
    936918E3, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117], O = B ? new Uint32Array(ka) : ka; function P() { } P.prototype.getName = function () { return this.name }; P.prototype.getData = function () { return this.data }; P.prototype.Y = function () { return this.Z }; A("Zlib.GunzipMember", P); A("Zlib.GunzipMember.prototype.getName", P.prototype.getName); A("Zlib.GunzipMember.prototype.getData", P.prototype.getData); A("Zlib.GunzipMember.prototype.getMtime", P.prototype.Y); function la(b) { this.buffer = new (B ? Uint16Array : Array)(2 * b); this.length = 0 } la.prototype.getParent = function (b) { return 2 * ((b - 2) / 4 | 0) }; la.prototype.push = function (b, a) { var c, d, e = this.buffer, f; c = this.length; e[this.length++] = a; for (e[this.length++] = b; 0 < c;) if (d = this.getParent(c), e[c] > e[d]) f = e[c], e[c] = e[d], e[d] = f, f = e[c + 1], e[c + 1] = e[d + 1], e[d + 1] = f, c = d; else break; return this.length };
    la.prototype.pop = function () { var b, a, c = this.buffer, d, e, f; a = c[0]; b = c[1]; this.length -= 2; c[0] = c[this.length]; c[1] = c[this.length + 1]; for (f = 0; ;) { e = 2 * f + 2; if (e >= this.length) break; e + 2 < this.length && c[e + 2] > c[e] && (e += 2); if (c[e] > c[f]) d = c[f], c[f] = c[e], c[e] = d, d = c[f + 1], c[f + 1] = c[e + 1], c[e + 1] = d; else break; f = e } return { index: b, value: a, length: this.length } }; function ma(b) { var a = b.length, c = 0, d = Number.POSITIVE_INFINITY, e, f, g, k, h, l, s, p, m, n; for (p = 0; p < a; ++p) b[p] > c && (c = b[p]), b[p] < d && (d = b[p]); e = 1 << c; f = new (B ? Uint32Array : Array)(e); g = 1; k = 0; for (h = 2; g <= c;) { for (p = 0; p < a; ++p) if (b[p] === g) { l = 0; s = k; for (m = 0; m < g; ++m) l = l << 1 | s & 1, s >>= 1; n = g << 16 | p; for (m = l; m < e; m += h) f[m] = n; ++k } ++g; k <<= 1; h <<= 1 } return [f, c, d] }; function na(b, a) { this.k = qa; this.I = 0; this.input = B && b instanceof Array ? new Uint8Array(b) : b; this.b = 0; a && (a.lazy && (this.I = a.lazy), "number" === typeof a.compressionType && (this.k = a.compressionType), a.outputBuffer && (this.a = B && a.outputBuffer instanceof Array ? new Uint8Array(a.outputBuffer) : a.outputBuffer), "number" === typeof a.outputIndex && (this.b = a.outputIndex)); this.a || (this.a = new (B ? Uint8Array : Array)(32768)) } var qa = 2, ra = { NONE: 0, v: 1, o: qa, ba: 3 }, sa = [], S;
    for (S = 0; 288 > S; S++) switch (u) { case 143 >= S: sa.push([S + 48, 8]); break; case 255 >= S: sa.push([S - 144 + 400, 9]); break; case 279 >= S: sa.push([S - 256 + 0, 7]); break; case 287 >= S: sa.push([S - 280 + 192, 8]); break; default: q("invalid literal: " + S) }
    na.prototype.g = function () {
        var b, a, c, d, e = this.input; switch (this.k) {
            case 0: c = 0; for (d = e.length; c < d;) {
                a = B ? e.subarray(c, c + 65535) : e.slice(c, c + 65535); c += a.length; var f = a, g = c === d, k = t, h = t, l = t, s = t, p = t, m = this.a, n = this.b; if (B) { for (m = new Uint8Array(this.a.buffer) ; m.length <= n + f.length + 5;) m = new Uint8Array(m.length << 1); m.set(this.a) } k = g ? 1 : 0; m[n++] = k | 0; h = f.length; l = ~h + 65536 & 65535; m[n++] = h & 255; m[n++] = h >>> 8 & 255; m[n++] = l & 255; m[n++] = l >>> 8 & 255; if (B) m.set(f, n), n += f.length, m = m.subarray(0, n); else {
                    s = 0; for (p = f.length; s < p; ++s) m[n++] =
                    f[s]; m.length = n
                } this.b = n; this.a = m
            } break; case 1: var r = new F(B ? new Uint8Array(this.a.buffer) : this.a, this.b); r.d(1, 1, u); r.d(1, 2, u); var v = ta(this, e), x, Q, y; x = 0; for (Q = v.length; x < Q; x++) if (y = v[x], F.prototype.d.apply(r, sa[y]), 256 < y) r.d(v[++x], v[++x], u), r.d(v[++x], 5), r.d(v[++x], v[++x], u); else if (256 === y) break; this.a = r.finish(); this.b = this.a.length; break; case qa: var E = new F(B ? new Uint8Array(this.a.buffer) : this.a, this.b), Ka, R, X, Y, Z, pb = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], fa, La, ga, Ma, oa, wa = Array(19),
            Na, $, pa, C, Oa; Ka = qa; E.d(1, 1, u); E.d(Ka, 2, u); R = ta(this, e); fa = ua(this.W, 15); La = va(fa); ga = ua(this.V, 7); Ma = va(ga); for (X = 286; 257 < X && 0 === fa[X - 1]; X--); for (Y = 30; 1 < Y && 0 === ga[Y - 1]; Y--); var Pa = X, Qa = Y, J = new (B ? Uint32Array : Array)(Pa + Qa), w, L, z, ha, I = new (B ? Uint32Array : Array)(316), G, D, M = new (B ? Uint8Array : Array)(19); for (w = L = 0; w < Pa; w++) J[L++] = fa[w]; for (w = 0; w < Qa; w++) J[L++] = ga[w]; if (!B) { w = 0; for (ha = M.length; w < ha; ++w) M[w] = 0 } w = G = 0; for (ha = J.length; w < ha; w += L) {
                for (L = 1; w + L < ha && J[w + L] === J[w]; ++L); z = L; if (0 === J[w]) if (3 > z) for (; 0 <
                z--;) I[G++] = 0, M[0]++; else for (; 0 < z;) D = 138 > z ? z : 138, D > z - 3 && D < z && (D = z - 3), 10 >= D ? (I[G++] = 17, I[G++] = D - 3, M[17]++) : (I[G++] = 18, I[G++] = D - 11, M[18]++), z -= D; else if (I[G++] = J[w], M[J[w]]++, z--, 3 > z) for (; 0 < z--;) I[G++] = J[w], M[J[w]]++; else for (; 0 < z;) D = 6 > z ? z : 6, D > z - 3 && D < z && (D = z - 3), I[G++] = 16, I[G++] = D - 3, M[16]++, z -= D
            } b = B ? I.subarray(0, G) : I.slice(0, G); oa = ua(M, 7); for (C = 0; 19 > C; C++) wa[C] = oa[pb[C]]; for (Z = 19; 4 < Z && 0 === wa[Z - 1]; Z--); Na = va(oa); E.d(X - 257, 5, u); E.d(Y - 1, 5, u); E.d(Z - 4, 4, u); for (C = 0; C < Z; C++) E.d(wa[C], 3, u); C = 0; for (Oa = b.length; C <
            Oa; C++) if ($ = b[C], E.d(Na[$], oa[$], u), 16 <= $) { C++; switch ($) { case 16: pa = 2; break; case 17: pa = 3; break; case 18: pa = 7; break; default: q("invalid code: " + $) } E.d(b[C], pa, u) } var Ra = [La, fa], Sa = [Ma, ga], N, Ta, ia, za, Ua, Va, Wa, Xa; Ua = Ra[0]; Va = Ra[1]; Wa = Sa[0]; Xa = Sa[1]; N = 0; for (Ta = R.length; N < Ta; ++N) if (ia = R[N], E.d(Ua[ia], Va[ia], u), 256 < ia) E.d(R[++N], R[++N], u), za = R[++N], E.d(Wa[za], Xa[za], u), E.d(R[++N], R[++N], u); else if (256 === ia) break; this.a = E.finish(); this.b = this.a.length; break; default: q("invalid compression type")
        } return this.a
    };
    function xa(b, a) { this.length = b; this.Q = a }
    var ya = function () {
        function b(a) {
            switch (u) {
                case 3 === a: return [257, a - 3, 0]; case 4 === a: return [258, a - 4, 0]; case 5 === a: return [259, a - 5, 0]; case 6 === a: return [260, a - 6, 0]; case 7 === a: return [261, a - 7, 0]; case 8 === a: return [262, a - 8, 0]; case 9 === a: return [263, a - 9, 0]; case 10 === a: return [264, a - 10, 0]; case 12 >= a: return [265, a - 11, 1]; case 14 >= a: return [266, a - 13, 1]; case 16 >= a: return [267, a - 15, 1]; case 18 >= a: return [268, a - 17, 1]; case 22 >= a: return [269, a - 19, 2]; case 26 >= a: return [270, a - 23, 2]; case 30 >= a: return [271, a - 27, 2]; case 34 >= a: return [272,
                a - 31, 2]; case 42 >= a: return [273, a - 35, 3]; case 50 >= a: return [274, a - 43, 3]; case 58 >= a: return [275, a - 51, 3]; case 66 >= a: return [276, a - 59, 3]; case 82 >= a: return [277, a - 67, 4]; case 98 >= a: return [278, a - 83, 4]; case 114 >= a: return [279, a - 99, 4]; case 130 >= a: return [280, a - 115, 4]; case 162 >= a: return [281, a - 131, 5]; case 194 >= a: return [282, a - 163, 5]; case 226 >= a: return [283, a - 195, 5]; case 257 >= a: return [284, a - 227, 5]; case 258 === a: return [285, a - 258, 0]; default: q("invalid length: " + a)
            }
        } var a = [], c, d; for (c = 3; 258 >= c; c++) d = b(c), a[c] = d[2] << 24 | d[1] <<
        16 | d[0]; return a
    }(), Aa = B ? new Uint32Array(ya) : ya;
    function ta(b, a) {
        function c(a, c) {
            var b = a.Q, d = [], e = 0, f; f = Aa[a.length]; d[e++] = f & 65535; d[e++] = f >> 16 & 255; d[e++] = f >> 24; var g; switch (u) {
                case 1 === b: g = [0, b - 1, 0]; break; case 2 === b: g = [1, b - 2, 0]; break; case 3 === b: g = [2, b - 3, 0]; break; case 4 === b: g = [3, b - 4, 0]; break; case 6 >= b: g = [4, b - 5, 1]; break; case 8 >= b: g = [5, b - 7, 1]; break; case 12 >= b: g = [6, b - 9, 2]; break; case 16 >= b: g = [7, b - 13, 2]; break; case 24 >= b: g = [8, b - 17, 3]; break; case 32 >= b: g = [9, b - 25, 3]; break; case 48 >= b: g = [10, b - 33, 4]; break; case 64 >= b: g = [11, b - 49, 4]; break; case 96 >= b: g = [12, b -
                65, 5]; break; case 128 >= b: g = [13, b - 97, 5]; break; case 192 >= b: g = [14, b - 129, 6]; break; case 256 >= b: g = [15, b - 193, 6]; break; case 384 >= b: g = [16, b - 257, 7]; break; case 512 >= b: g = [17, b - 385, 7]; break; case 768 >= b: g = [18, b - 513, 8]; break; case 1024 >= b: g = [19, b - 769, 8]; break; case 1536 >= b: g = [20, b - 1025, 9]; break; case 2048 >= b: g = [21, b - 1537, 9]; break; case 3072 >= b: g = [22, b - 2049, 10]; break; case 4096 >= b: g = [23, b - 3073, 10]; break; case 6144 >= b: g = [24, b - 4097, 11]; break; case 8192 >= b: g = [25, b - 6145, 11]; break; case 12288 >= b: g = [26, b - 8193, 12]; break; case 16384 >=
                    b: g = [27, b - 12289, 12]; break; case 24576 >= b: g = [28, b - 16385, 13]; break; case 32768 >= b: g = [29, b - 24577, 13]; break; default: q("invalid distance")
            } f = g; d[e++] = f[0]; d[e++] = f[1]; d[e++] = f[2]; var h, k; h = 0; for (k = d.length; h < k; ++h) m[n++] = d[h]; v[d[0]]++; x[d[3]]++; r = a.length + c - 1; p = null
        } var d, e, f, g, k, h = {}, l, s, p, m = B ? new Uint16Array(2 * a.length) : [], n = 0, r = 0, v = new (B ? Uint32Array : Array)(286), x = new (B ? Uint32Array : Array)(30), Q = b.I, y; if (!B) { for (f = 0; 285 >= f;) v[f++] = 0; for (f = 0; 29 >= f;) x[f++] = 0 } v[256] = 1; d = 0; for (e = a.length; d < e; ++d) {
            f = k = 0;
            for (g = 3; f < g && d + f !== e; ++f) k = k << 8 | a[d + f]; h[k] === t && (h[k] = []); l = h[k]; if (!(0 < r--)) { for (; 0 < l.length && 32768 < d - l[0];) l.shift(); if (d + 3 >= e) { p && c(p, -1); f = 0; for (g = e - d; f < g; ++f) y = a[d + f], m[n++] = y, ++v[y]; break } 0 < l.length ? (s = Ba(a, d, l), p ? p.length < s.length ? (y = a[d - 1], m[n++] = y, ++v[y], c(s, 0)) : c(p, -1) : s.length < Q ? p = s : c(s, 0)) : p ? c(p, -1) : (y = a[d], m[n++] = y, ++v[y]) } l.push(d)
        } m[n++] = 256; v[256]++; b.W = v; b.V = x; return B ? m.subarray(0, n) : m
    }
    function Ba(b, a, c) { var d, e, f = 0, g, k, h, l, s = b.length; k = 0; l = c.length; a: for (; k < l; k++) { d = c[l - k - 1]; g = 3; if (3 < f) { for (h = f; 3 < h; h--) if (b[d + h - 1] !== b[a + h - 1]) continue a; g = f } for (; 258 > g && a + g < s && b[d + g] === b[a + g];)++g; g > f && (e = d, f = g); if (258 === g) break } return new xa(f, a - e) }
    function ua(b, a) { var c = b.length, d = new la(572), e = new (B ? Uint8Array : Array)(c), f, g, k, h, l; if (!B) for (h = 0; h < c; h++) e[h] = 0; for (h = 0; h < c; ++h) 0 < b[h] && d.push(h, b[h]); f = Array(d.length / 2); g = new (B ? Uint32Array : Array)(d.length / 2); if (1 === f.length) return e[d.pop().index] = 1, e; h = 0; for (l = d.length / 2; h < l; ++h) f[h] = d.pop(), g[h] = f[h].value; k = Ca(g, g.length, a); h = 0; for (l = f.length; h < l; ++h) e[f[h].index] = k[h]; return e }
    function Ca(b, a, c) {
        function d(b) { var c = h[b][l[b]]; c === a ? (d(b + 1), d(b + 1)) : --g[c]; ++l[b] } var e = new (B ? Uint16Array : Array)(c), f = new (B ? Uint8Array : Array)(c), g = new (B ? Uint8Array : Array)(a), k = Array(c), h = Array(c), l = Array(c), s = (1 << c) - a, p = 1 << c - 1, m, n, r, v, x; e[c - 1] = a; for (n = 0; n < c; ++n) s < p ? f[n] = 0 : (f[n] = 1, s -= p), s <<= 1, e[c - 2 - n] = (e[c - 1 - n] / 2 | 0) + a; e[0] = f[0]; k[0] = Array(e[0]); h[0] = Array(e[0]); for (n = 1; n < c; ++n) e[n] > 2 * e[n - 1] + f[n] && (e[n] = 2 * e[n - 1] + f[n]), k[n] = Array(e[n]), h[n] = Array(e[n]); for (m = 0; m < a; ++m) g[m] = c; for (r = 0; r < e[c - 1]; ++r) k[c -
        1][r] = b[r], h[c - 1][r] = r; for (m = 0; m < c; ++m) l[m] = 0; 1 === f[c - 1] && (--g[0], ++l[c - 1]); for (n = c - 2; 0 <= n; --n) { v = m = 0; x = l[n + 1]; for (r = 0; r < e[n]; r++) v = k[n + 1][x] + k[n + 1][x + 1], v > b[m] ? (k[n][r] = v, h[n][r] = a, x += 2) : (k[n][r] = b[m], h[n][r] = m, ++m); l[n] = 0; 1 === f[n] && d(n) } return g
    }
    function va(b) { var a = new (B ? Uint16Array : Array)(b.length), c = [], d = [], e = 0, f, g, k, h; f = 0; for (g = b.length; f < g; f++) c[b[f]] = (c[b[f]] | 0) + 1; f = 1; for (g = 16; f <= g; f++) d[f] = e, e += c[f] | 0, e <<= 1; f = 0; for (g = b.length; f < g; f++) { e = d[b[f]]; d[b[f]] += 1; k = a[f] = 0; for (h = b[f]; k < h; k++) a[f] = a[f] << 1 | e & 1, e >>>= 1 } return a }; function Da(b, a) { this.input = b; this.b = this.c = 0; this.i = {}; a && (a.flags && (this.i = a.flags), "string" === typeof a.filename && (this.filename = a.filename), "string" === typeof a.comment && (this.A = a.comment), a.deflateOptions && (this.l = a.deflateOptions)); this.l || (this.l = {}) }
    Da.prototype.g = function () {
        var b, a, c, d, e, f, g, k, h = new (B ? Uint8Array : Array)(32768), l = 0, s = this.input, p = this.c, m = this.filename, n = this.A; h[l++] = 31; h[l++] = 139; h[l++] = 8; b = 0; this.i.fname && (b |= Ea); this.i.fcomment && (b |= Fa); this.i.fhcrc && (b |= Ga); h[l++] = b; a = (Date.now ? Date.now() : +new Date) / 1E3 | 0; h[l++] = a & 255; h[l++] = a >>> 8 & 255; h[l++] = a >>> 16 & 255; h[l++] = a >>> 24 & 255; h[l++] = 0; h[l++] = Ha; if (this.i.fname !== t) { g = 0; for (k = m.length; g < k; ++g) f = m.charCodeAt(g), 255 < f && (h[l++] = f >>> 8 & 255), h[l++] = f & 255; h[l++] = 0 } if (this.i.comment) {
            g =
            0; for (k = n.length; g < k; ++g) f = n.charCodeAt(g), 255 < f && (h[l++] = f >>> 8 & 255), h[l++] = f & 255; h[l++] = 0
        } this.i.fhcrc && (c = ja(h, 0, l) & 65535, h[l++] = c & 255, h[l++] = c >>> 8 & 255); this.l.outputBuffer = h; this.l.outputIndex = l; e = new na(s, this.l); h = e.g(); l = e.b; B && (l + 8 > h.buffer.byteLength ? (this.a = new Uint8Array(l + 8), this.a.set(new Uint8Array(h.buffer)), h = this.a) : h = new Uint8Array(h.buffer)); d = ja(s, t, t); h[l++] = d & 255; h[l++] = d >>> 8 & 255; h[l++] = d >>> 16 & 255; h[l++] = d >>> 24 & 255; k = s.length; h[l++] = k & 255; h[l++] = k >>> 8 & 255; h[l++] = k >>> 16 & 255; h[l++] =
        k >>> 24 & 255; this.c = p; B && l < h.length && (this.a = h = h.subarray(0, l)); return h
    }; var Ha = 255, Ga = 2, Ea = 8, Fa = 16; A("Zlib.Gzip", Da); A("Zlib.Gzip.prototype.compress", Da.prototype.g); function T(b, a) { this.p = []; this.q = 32768; this.e = this.j = this.c = this.u = 0; this.input = B ? new Uint8Array(b) : b; this.w = !1; this.r = Ia; this.M = !1; if (a || !(a = {})) a.index && (this.c = a.index), a.bufferSize && (this.q = a.bufferSize), a.bufferType && (this.r = a.bufferType), a.resize && (this.M = a.resize); switch (this.r) { case Ja: this.b = 32768; this.a = new (B ? Uint8Array : Array)(32768 + this.q + 258); break; case Ia: this.b = 0; this.a = new (B ? Uint8Array : Array)(this.q); this.f = this.U; this.B = this.R; this.s = this.T; break; default: q(Error("invalid inflate mode")) } }
    var Ja = 0, Ia = 1, Ya = { O: Ja, N: Ia };
    T.prototype.h = function () {
        for (; !this.w;) {
            var b = U(this, 3); b & 1 && (this.w = u); b >>>= 1; switch (b) {
                case 0: var a = this.input, c = this.c, d = this.a, e = this.b, f = a.length, g = t, k = t, h = d.length, l = t; this.e = this.j = 0; c + 1 >= f && q(Error("invalid uncompressed block header: LEN")); g = a[c++] | a[c++] << 8; c + 1 >= f && q(Error("invalid uncompressed block header: NLEN")); k = a[c++] | a[c++] << 8; g === ~k && q(Error("invalid uncompressed block header: length verify")); c + g > a.length && q(Error("input buffer is broken")); switch (this.r) {
                    case Ja: for (; e + g > d.length;) {
                        l =
                        h - e; g -= l; if (B) d.set(a.subarray(c, c + l), e), e += l, c += l; else for (; l--;) d[e++] = a[c++]; this.b = e; d = this.f(); e = this.b
                    } break; case Ia: for (; e + g > d.length;) d = this.f({ F: 2 }); break; default: q(Error("invalid inflate mode"))
                } if (B) d.set(a.subarray(c, c + g), e), e += g, c += g; else for (; g--;) d[e++] = a[c++]; this.c = c; this.b = e; this.a = d; break; case 1: this.s(Za, $a); break; case 2: ab(this); break; default: q(Error("unknown BTYPE: " + b))
            }
        } return this.B()
    };
    var bb = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], cb = B ? new Uint16Array(bb) : bb, db = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 258, 258], eb = B ? new Uint16Array(db) : db, fb = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0], gb = B ? new Uint8Array(fb) : fb, hb = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577], ib = B ? new Uint16Array(hb) : hb, jb = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
    10, 11, 11, 12, 12, 13, 13], kb = B ? new Uint8Array(jb) : jb, lb = new (B ? Uint8Array : Array)(288), V, mb; V = 0; for (mb = lb.length; V < mb; ++V) lb[V] = 143 >= V ? 8 : 255 >= V ? 9 : 279 >= V ? 7 : 8; var Za = ma(lb), nb = new (B ? Uint8Array : Array)(30), ob, qb; ob = 0; for (qb = nb.length; ob < qb; ++ob) nb[ob] = 5; var $a = ma(nb); function U(b, a) { for (var c = b.j, d = b.e, e = b.input, f = b.c, g = e.length, k; d < a;) f >= g && q(Error("input buffer is broken")), c |= e[f++] << d, d += 8; k = c & (1 << a) - 1; b.j = c >>> a; b.e = d - a; b.c = f; return k }
    function rb(b, a) { for (var c = b.j, d = b.e, e = b.input, f = b.c, g = e.length, k = a[0], h = a[1], l, s; d < h && !(f >= g) ;) c |= e[f++] << d, d += 8; l = k[c & (1 << h) - 1]; s = l >>> 16; b.j = c >> s; b.e = d - s; b.c = f; return l & 65535 }
    function ab(b) {
        function a(a, b, c) { var d, e = this.J, f, g; for (g = 0; g < a;) switch (d = rb(this, b), d) { case 16: for (f = 3 + U(this, 2) ; f--;) c[g++] = e; break; case 17: for (f = 3 + U(this, 3) ; f--;) c[g++] = 0; e = 0; break; case 18: for (f = 11 + U(this, 7) ; f--;) c[g++] = 0; e = 0; break; default: e = c[g++] = d } this.J = e; return c } var c = U(b, 5) + 257, d = U(b, 5) + 1, e = U(b, 4) + 4, f = new (B ? Uint8Array : Array)(cb.length), g, k, h, l; for (l = 0; l < e; ++l) f[cb[l]] = U(b, 3); if (!B) { l = e; for (e = f.length; l < e; ++l) f[cb[l]] = 0 } g = ma(f); k = new (B ? Uint8Array : Array)(c); h = new (B ? Uint8Array : Array)(d);
        b.J = 0; b.s(ma(a.call(b, c, g, k)), ma(a.call(b, d, g, h)))
    } T.prototype.s = function (b, a) { var c = this.a, d = this.b; this.C = b; for (var e = c.length - 258, f, g, k, h; 256 !== (f = rb(this, b)) ;) if (256 > f) d >= e && (this.b = d, c = this.f(), d = this.b), c[d++] = f; else { g = f - 257; h = eb[g]; 0 < gb[g] && (h += U(this, gb[g])); f = rb(this, a); k = ib[f]; 0 < kb[f] && (k += U(this, kb[f])); d >= e && (this.b = d, c = this.f(), d = this.b); for (; h--;) c[d] = c[d++ - k] } for (; 8 <= this.e;) this.e -= 8, this.c--; this.b = d };
    T.prototype.T = function (b, a) { var c = this.a, d = this.b; this.C = b; for (var e = c.length, f, g, k, h; 256 !== (f = rb(this, b)) ;) if (256 > f) d >= e && (c = this.f(), e = c.length), c[d++] = f; else { g = f - 257; h = eb[g]; 0 < gb[g] && (h += U(this, gb[g])); f = rb(this, a); k = ib[f]; 0 < kb[f] && (k += U(this, kb[f])); d + h > e && (c = this.f(), e = c.length); for (; h--;) c[d] = c[d++ - k] } for (; 8 <= this.e;) this.e -= 8, this.c--; this.b = d };
    T.prototype.f = function () { var b = new (B ? Uint8Array : Array)(this.b - 32768), a = this.b - 32768, c, d, e = this.a; if (B) b.set(e.subarray(32768, b.length)); else { c = 0; for (d = b.length; c < d; ++c) b[c] = e[c + 32768] } this.p.push(b); this.u += b.length; if (B) e.set(e.subarray(a, a + 32768)); else for (c = 0; 32768 > c; ++c) e[c] = e[a + c]; this.b = 32768; return e };
    T.prototype.U = function (b) { var a, c = this.input.length / this.c + 1 | 0, d, e, f, g = this.input, k = this.a; b && ("number" === typeof b.F && (c = b.F), "number" === typeof b.P && (c += b.P)); 2 > c ? (d = (g.length - this.c) / this.C[2], f = 258 * (d / 2) | 0, e = f < k.length ? k.length + f : k.length << 1) : e = k.length * c; B ? (a = new Uint8Array(e), a.set(k)) : a = k; return this.a = a };
    T.prototype.B = function () { var b = 0, a = this.a, c = this.p, d, e = new (B ? Uint8Array : Array)(this.u + (this.b - 32768)), f, g, k, h; if (0 === c.length) return B ? this.a.subarray(32768, this.b) : this.a.slice(32768, this.b); f = 0; for (g = c.length; f < g; ++f) { d = c[f]; k = 0; for (h = d.length; k < h; ++k) e[b++] = d[k] } f = 32768; for (g = this.b; f < g; ++f) e[b++] = a[f]; this.p = []; return this.buffer = e };
    T.prototype.R = function () { var b, a = this.b; B ? this.M ? (b = new Uint8Array(a), b.set(this.a.subarray(0, a))) : b = this.a.subarray(0, a) : (this.a.length > a && (this.a.length = a), b = this.a); return this.buffer = b }; function sb(b) { this.input = b; this.c = 0; this.t = []; this.D = !1 } sb.prototype.X = function () { this.D || this.h(); return this.t.slice() };
    sb.prototype.h = function () {
        for (var b = this.input.length; this.c < b;) {
            var a = new P, c = t, d = t, e = t, f = t, g = t, k = t, h = t, l = t, s = t, p = this.input, m = this.c; a.G = p[m++]; a.H = p[m++]; (31 !== a.G || 139 !== a.H) && q(Error("invalid file signature:" + a.G + "," + a.H)); a.z = p[m++]; switch (a.z) { case 8: break; default: q(Error("unknown compression method: " + a.z)) } a.n = p[m++]; l = p[m++] | p[m++] << 8 | p[m++] << 16 | p[m++] << 24; a.Z = new Date(1E3 * l); a.fa = p[m++]; a.ea = p[m++]; 0 < (a.n & 4) && (a.aa = p[m++] | p[m++] << 8, m += a.aa); if (0 < (a.n & Ea)) {
                h = []; for (k = 0; 0 < (g = p[m++]) ;) h[k++] =
                String.fromCharCode(g); a.name = h.join("")
            } if (0 < (a.n & Fa)) { h = []; for (k = 0; 0 < (g = p[m++]) ;) h[k++] = String.fromCharCode(g); a.A = h.join("") } 0 < (a.n & Ga) && (a.S = ja(p, 0, m) & 65535, a.S !== (p[m++] | p[m++] << 8) && q(Error("invalid header crc16"))); c = p[p.length - 4] | p[p.length - 3] << 8 | p[p.length - 2] << 16 | p[p.length - 1] << 24; p.length - m - 4 - 4 < 512 * c && (f = c); d = new T(p, { index: m, bufferSize: f }); a.data = e = d.h(); m = d.c; a.ca = s = (p[m++] | p[m++] << 8 | p[m++] << 16 | p[m++] << 24) >>> 0; ja(e, t, t) !== s && q(Error("invalid CRC-32 checksum: 0x" + ja(e, t, t).toString(16) +
            " / 0x" + s.toString(16))); a.da = c = (p[m++] | p[m++] << 8 | p[m++] << 16 | p[m++] << 24) >>> 0; (e.length & 4294967295) !== c && q(Error("invalid input size: " + (e.length & 4294967295) + " / " + c)); this.t.push(a); this.c = m
        } this.D = u; var n = this.t, r, v, x = 0, Q = 0, y; r = 0; for (v = n.length; r < v; ++r) Q += n[r].data.length; if (B) { y = new Uint8Array(Q); for (r = 0; r < v; ++r) y.set(n[r].data, x), x += n[r].data.length } else { y = []; for (r = 0; r < v; ++r) y[r] = n[r].data; y = Array.prototype.concat.apply([], y) } return y
    }; A("Zlib.Gunzip", sb); A("Zlib.Gunzip.prototype.decompress", sb.prototype.h); A("Zlib.Gunzip.prototype.getMembers", sb.prototype.X); function tb(b) { if ("string" === typeof b) { var a = b.split(""), c, d; c = 0; for (d = a.length; c < d; c++) a[c] = (a[c].charCodeAt(0) & 255) >>> 0; b = a } for (var e = 1, f = 0, g = b.length, k, h = 0; 0 < g;) { k = 1024 < g ? 1024 : g; g -= k; do e += b[h++], f += e; while (--k); e %= 65521; f %= 65521 } return (f << 16 | e) >>> 0 }; function ub(b, a) { var c, d; this.input = b; this.c = 0; if (a || !(a = {})) a.index && (this.c = a.index), a.verify && (this.$ = a.verify); c = b[this.c++]; d = b[this.c++]; switch (c & 15) { case vb: this.method = vb; break; default: q(Error("unsupported compression method")) } 0 !== ((c << 8) + d) % 31 && q(Error("invalid fcheck flag:" + ((c << 8) + d) % 31)); d & 32 && q(Error("fdict flag is not supported")); this.L = new T(b, { index: this.c, bufferSize: a.bufferSize, bufferType: a.bufferType, resize: a.resize }) }
    ub.prototype.h = function () { var b = this.input, a, c; a = this.L.h(); this.c = this.L.c; this.$ && (c = (b[this.c++] << 24 | b[this.c++] << 16 | b[this.c++] << 8 | b[this.c++]) >>> 0, c !== tb(a) && q(Error("invalid adler-32 checksum"))); return a }; var vb = 8; function wb(b, a) { this.input = b; this.a = new (B ? Uint8Array : Array)(32768); this.k = W.o; var c = {}, d; if ((a || !(a = {})) && "number" === typeof a.compressionType) this.k = a.compressionType; for (d in a) c[d] = a[d]; c.outputBuffer = this.a; this.K = new na(this.input, c) } var W = ra;
    wb.prototype.g = function () {
        var b, a, c, d, e, f, g, k = 0; g = this.a; b = vb; switch (b) { case vb: a = Math.LOG2E * Math.log(32768) - 8; break; default: q(Error("invalid compression method")) } c = a << 4 | b; g[k++] = c; switch (b) { case vb: switch (this.k) { case W.NONE: e = 0; break; case W.v: e = 1; break; case W.o: e = 2; break; default: q(Error("unsupported compression type")) } break; default: q(Error("invalid compression method")) } d = e << 6 | 0; g[k++] = d | 31 - (256 * c + d) % 31; f = tb(this.input); this.K.b = k; g = this.K.g(); k = g.length; B && (g = new Uint8Array(g.buffer), g.length <=
        k + 4 && (this.a = new Uint8Array(g.length + 4), this.a.set(g), g = this.a), g = g.subarray(0, k + 4)); g[k++] = f >> 24 & 255; g[k++] = f >> 16 & 255; g[k++] = f >> 8 & 255; g[k++] = f & 255; return g
    }; function xb(b, a) { var c, d, e, f; if (Object.keys) c = Object.keys(a); else for (d in c = [], e = 0, a) c[e++] = d; e = 0; for (f = c.length; e < f; ++e) d = c[e], A(b + "." + d, a[d]) }; A("Zlib.Inflate", ub); A("Zlib.Inflate.prototype.decompress", ub.prototype.h); xb("Zlib.Inflate.BufferType", { ADAPTIVE: Ya.N, BLOCK: Ya.O }); A("Zlib.Deflate", wb); A("Zlib.Deflate.compress", function (b, a) { return (new wb(b, a)).g() }); A("Zlib.Deflate.prototype.compress", wb.prototype.g); xb("Zlib.Deflate.CompressionType", { NONE: W.NONE, FIXED: W.v, DYNAMIC: W.o });
}).call(__LiteMolZlib); 
var LiteMolZlib = __LiteMolZlib.Zlib;


/**
 * React v15.6.1
 *
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 */

/*

BSD License

For React software

Copyright (c) 2013-present, Facebook, 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 Facebook 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.

*/

var __LiteMolReact;
(function() {

    var exports = {};
    var __module__ = {};

!function(t){if("object"==typeof exports&&"undefined"!=typeof __module__)__module__.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.React=t()}}(function(){return function t(e,n,r){function o(a,u){if(!n[a]){if(!e[a]){var s=void 0;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find __module__ '"+a+"'");throw c.code="__module___NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n||t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i=void 0,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(t,e,n){"use strict";function r(t){var e={"=":"=0",":":"=2"};return"$"+(""+t).replace(/[=:]/g,function(t){return e[t]})}function o(t){var e=/(=0|=2)/g,n={"=0":"=","=2":":"};return(""+("."===t[0]&&"$"===t[1]?t.substring(2):t.substring(1))).replace(e,function(t){return n[t]})}var i={escape:r,unescape:o};e.exports=i},{}],2:[function(t,e,n){"use strict";var r=t(19),o=(t(24),function(t){var e=this;if(e.instancePool.length){var n=e.instancePool.pop();return e.call(n,t),n}return new e(t)}),i=function(t,e){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,t,e),r}return new n(t,e)},a=function(t,e,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,t,e,n),o}return new r(t,e,n)},u=function(t,e,n,r){var o=this;if(o.instancePool.length){var i=o.instancePool.pop();return o.call(i,t,e,n,r),i}return new o(t,e,n,r)},s=function(t){var e=this;t instanceof e||r("25"),t.destructor(),e.instancePool.length<e.poolSize&&e.instancePool.push(t)},c=o,l=function(t,e){var n=t;return n.instancePool=[],n.getPooled=e||c,n.poolSize||(n.poolSize=10),n.release=s,n},f={addPoolingTo:l,oneArgumentPooler:o,twoArgumentPooler:i,threeArgumentPooler:a,fourArgumentPooler:u};e.exports=f},{19:19,24:24}],3:[function(t,e,n){"use strict";var r=t(26),o=t(4),i=t(5),a=t(7),u=t(8),s=t(11),c=t(13),l=t(15),f=t(18),p=u.createElement,d=u.createFactory,y=u.cloneElement,h=r,m=function(t){return t},v={Children:{map:i.map,forEach:i.forEach,count:i.count,toArray:i.toArray,only:f},Component:o.Component,PureComponent:o.PureComponent,createElement:p,cloneElement:y,isValidElement:u.isValidElement,PropTypes:s,createClass:l,createFactory:d,createMixin:m,DOM:a,version:c,__spread:h};e.exports=v},{11:11,13:13,15:15,18:18,26:26,4:4,5:5,7:7,8:8}],4:[function(t,e,n){"use strict";function r(t,e,n){this.props=t,this.context=e,this.refs=c,this.updater=n||s}function o(t,e,n){this.props=t,this.context=e,this.refs=c,this.updater=n||s}function i(){}var a=t(19),u=t(26),s=t(10),c=(t(14),t(23));t(24),t(17);r.prototype.isReactComponent={},r.prototype.setState=function(t,e){"object"!=typeof t&&"function"!=typeof t&&null!=t&&a("85"),this.updater.enqueueSetState(this,t),e&&this.updater.enqueueCallback(this,e,"setState")},r.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this),t&&this.updater.enqueueCallback(this,t,"forceUpdate")};i.prototype=r.prototype,o.prototype=new i,o.prototype.constructor=o,u(o.prototype,r.prototype),o.prototype.isPureReactComponent=!0,e.exports={Component:r,PureComponent:o}},{10:10,14:14,17:17,19:19,23:23,24:24,26:26}],5:[function(t,e,n){"use strict";function r(t){return(""+t).replace(E,"$&/")}function o(t,e){this.func=t,this.context=e,this.count=0}function i(t,e,n){var r=t.func,o=t.context;r.call(o,e,t.count++)}function a(t,e,n){if(null==t)return t;var r=o.getPooled(e,n);v(t,i,r),o.release(r)}function u(t,e,n,r){this.result=t,this.keyPrefix=e,this.func=n,this.context=r,this.count=0}function s(t,e,n){var o=t.result,i=t.keyPrefix,a=t.func,u=t.context,s=a.call(u,e,t.count++);Array.isArray(s)?c(s,o,n,m.thatReturnsArgument):null!=s&&(h.isValidElement(s)&&(s=h.cloneAndReplaceKey(s,i+(!s.key||e&&e.key===s.key?"":r(s.key)+"/")+n)),o.push(s))}function c(t,e,n,o,i){var a="";null!=n&&(a=r(n)+"/");var c=u.getPooled(e,a,o,i);v(t,s,c),u.release(c)}function l(t,e,n){if(null==t)return t;var r=[];return c(t,r,null,e,n),r}function f(t,e,n){return null}function p(t,e){return v(t,f,null)}function d(t){var e=[];return c(t,e,null,m.thatReturnsArgument),e}var y=t(2),h=t(8),m=t(22),v=t(20),b=y.twoArgumentPooler,g=y.fourArgumentPooler,E=/\/+/g;o.prototype.destructor=function(){this.func=null,this.context=null,this.count=0},y.addPoolingTo(o,b),u.prototype.destructor=function(){this.result=null,this.keyPrefix=null,this.func=null,this.context=null,this.count=0},y.addPoolingTo(u,g);var x={forEach:a,map:l,mapIntoWithKeyPrefixInternal:c,count:p,toArray:d};e.exports=x},{2:2,20:20,22:22,8:8}],6:[function(t,e,n){"use strict";var r={current:null};e.exports=r},{}],7:[function(t,e,n){"use strict";var r=t(8),o=r.createFactory,i={a:o("a"),abbr:o("abbr"),address:o("address"),area:o("area"),article:o("article"),aside:o("aside"),audio:o("audio"),b:o("b"),base:o("base"),bdi:o("bdi"),bdo:o("bdo"),big:o("big"),blockquote:o("blockquote"),body:o("body"),br:o("br"),button:o("button"),canvas:o("canvas"),caption:o("caption"),cite:o("cite"),code:o("code"),col:o("col"),colgroup:o("colgroup"),data:o("data"),datalist:o("datalist"),dd:o("dd"),del:o("del"),details:o("details"),dfn:o("dfn"),dialog:o("dialog"),div:o("div"),dl:o("dl"),dt:o("dt"),em:o("em"),embed:o("embed"),fieldset:o("fieldset"),figcaption:o("figcaption"),figure:o("figure"),footer:o("footer"),form:o("form"),h1:o("h1"),h2:o("h2"),h3:o("h3"),h4:o("h4"),h5:o("h5"),h6:o("h6"),head:o("head"),header:o("header"),hgroup:o("hgroup"),hr:o("hr"),html:o("html"),i:o("i"),iframe:o("iframe"),img:o("img"),input:o("input"),ins:o("ins"),kbd:o("kbd"),keygen:o("keygen"),label:o("label"),legend:o("legend"),li:o("li"),link:o("link"),main:o("main"),map:o("map"),mark:o("mark"),menu:o("menu"),menuitem:o("menuitem"),meta:o("meta"),meter:o("meter"),nav:o("nav"),noscript:o("noscript"),object:o("object"),ol:o("ol"),optgroup:o("optgroup"),option:o("option"),output:o("output"),p:o("p"),param:o("param"),picture:o("picture"),pre:o("pre"),progress:o("progress"),q:o("q"),rp:o("rp"),rt:o("rt"),ruby:o("ruby"),s:o("s"),samp:o("samp"),script:o("script"),section:o("section"),select:o("select"),small:o("small"),source:o("source"),span:o("span"),strong:o("strong"),style:o("style"),sub:o("sub"),summary:o("summary"),sup:o("sup"),table:o("table"),tbody:o("tbody"),td:o("td"),textarea:o("textarea"),tfoot:o("tfoot"),th:o("th"),thead:o("thead"),time:o("time"),title:o("title"),tr:o("tr"),track:o("track"),u:o("u"),ul:o("ul"),var:o("var"),video:o("video"),wbr:o("wbr"),circle:o("circle"),clipPath:o("clipPath"),defs:o("defs"),ellipse:o("ellipse"),g:o("g"),image:o("image"),line:o("line"),linearGradient:o("linearGradient"),mask:o("mask"),path:o("path"),pattern:o("pattern"),polygon:o("polygon"),polyline:o("polyline"),radialGradient:o("radialGradient"),rect:o("rect"),stop:o("stop"),svg:o("svg"),text:o("text"),tspan:o("tspan")};e.exports=i},{8:8}],8:[function(t,e,n){"use strict";function r(t){return void 0!==t.ref}function o(t){return void 0!==t.key}var i=t(26),a=t(6),u=(t(25),t(14),Object.prototype.hasOwnProperty),s=t(9),c={key:!0,ref:!0,__self:!0,__source:!0},l=function(t,e,n,r,o,i,a){return{$$typeof:s,type:t,key:e,ref:n,props:a,_owner:i}};l.createElement=function(t,e,n){var i,s={},f=null,p=null;if(null!=e){r(e)&&(p=e.ref),o(e)&&(f=""+e.key),void 0===e.__self?null:e.__self,void 0===e.__source?null:e.__source;for(i in e)u.call(e,i)&&!c.hasOwnProperty(i)&&(s[i]=e[i])}var d=arguments.length-2;if(1===d)s.children=n;else if(d>1){for(var y=Array(d),h=0;h<d;h++)y[h]=arguments[h+2];s.children=y}if(t&&t.defaultProps){var m=t.defaultProps;for(i in m)void 0===s[i]&&(s[i]=m[i])}return l(t,f,p,0,0,a.current,s)},l.createFactory=function(t){var e=l.createElement.bind(null,t);return e.type=t,e},l.cloneAndReplaceKey=function(t,e){return l(t.type,e,t.ref,t._self,t._source,t._owner,t.props)},l.cloneElement=function(t,e,n){var s,f=i({},t.props),p=t.key,d=t.ref,y=(t._self,t._source,t._owner);if(null!=e){r(e)&&(d=e.ref,y=a.current),o(e)&&(p=""+e.key);var h;t.type&&t.type.defaultProps&&(h=t.type.defaultProps);for(s in e)u.call(e,s)&&!c.hasOwnProperty(s)&&(void 0===e[s]&&void 0!==h?f[s]=h[s]:f[s]=e[s])}var m=arguments.length-2;if(1===m)f.children=n;else if(m>1){for(var v=Array(m),b=0;b<m;b++)v[b]=arguments[b+2];f.children=v}return l(t.type,p,d,0,0,y,f)},l.isValidElement=function(t){return"object"==typeof t&&null!==t&&t.$$typeof===s},e.exports=l},{14:14,25:25,26:26,6:6,9:9}],9:[function(t,e,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;e.exports=r},{}],10:[function(t,e,n){"use strict";var r=(t(25),{isMounted:function(t){return!1},enqueueCallback:function(t,e){},enqueueForceUpdate:function(t){},enqueueReplaceState:function(t,e){},enqueueSetState:function(t,e){}});e.exports=r},{25:25}],11:[function(t,e,n){"use strict";var r=t(8),o=r.isValidElement,i=t(28);e.exports=i(o)},{28:28,8:8}],12:[function(t,e,n){"use strict";var r=t(26),o=t(3),i=r(o,{__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:t(6)}});e.exports=i},{26:26,3:3,6:6}],13:[function(t,e,n){"use strict";e.exports="15.6.1"},{}],14:[function(t,e,n){"use strict";e.exports=!1},{}],15:[function(t,e,n){"use strict";var r=t(4),o=r.Component,i=t(8),a=i.isValidElement,u=t(10),s=t(21);e.exports=s(o,a,u)},{10:10,21:21,4:4,8:8}],16:[function(t,e,n){"use strict";function r(t){var e=t&&(o&&t[o]||t[i]);if("function"==typeof e)return e}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";e.exports=r},{}],17:[function(t,e,n){"use strict";var r=function(){};e.exports=r},{}],18:[function(t,e,n){"use strict";function r(t){return i.isValidElement(t)||o("143"),t}var o=t(19),i=t(8);t(24);e.exports=r},{19:19,24:24,8:8}],19:[function(t,e,n){"use strict";function r(t){for(var e=arguments.length-1,n="Minified React error #"+t+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+t,r=0;r<e;r++)n+="&args[]="+encodeURIComponent(arguments[r+1]);n+=" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";var o=new Error(n);throw o.name="Invariant Violation",o.framesToPop=1,o}e.exports=r},{}],20:[function(t,e,n){"use strict";function r(t,e){return t&&"object"==typeof t&&null!=t.key?c.escape(t.key):e.toString(36)}function o(t,e,n,i){var p=typeof t;if("undefined"!==p&&"boolean"!==p||(t=null),null===t||"string"===p||"number"===p||"object"===p&&t.$$typeof===u)return n(i,t,""===e?l+r(t,0):e),1;var d,y,h=0,m=""===e?l:e+f;if(Array.isArray(t))for(var v=0;v<t.length;v++)d=t[v],y=m+r(d,v),h+=o(d,y,n,i);else{var b=s(t);if(b){var g,E=b.call(t);if(b!==t.entries)for(var x=0;!(g=E.next()).done;)d=g.value,y=m+r(d,x++),h+=o(d,y,n,i);else for(;!(g=E.next()).done;){var _=g.value;_&&(d=_[1],y=m+c.escape(_[0])+f+r(d,0),h+=o(d,y,n,i))}}else if("object"===p){var P=String(t);a("31","[object Object]"===P?"object with keys {"+Object.keys(t).join(", ")+"}":P,"")}}return h}function i(t,e,n){return null==t?0:o(t,"",e,n)}var a=t(19),u=(t(6),t(9)),s=t(16),c=(t(24),t(1)),l=(t(25),"."),f=":";e.exports=i},{1:1,16:16,19:19,24:24,25:25,6:6,9:9}],21:[function(t,e,n){"use strict";function r(t){return t}function o(t,e,n){function o(t,e){var n=b.hasOwnProperty(e)?b[e]:null;_.hasOwnProperty(e)&&u("OVERRIDE_BASE"===n,"ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.",e),t&&u("DEFINE_MANY"===n||"DEFINE_MANY_MERGED"===n,"ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",e)}function c(t,n){if(n){u("function"!=typeof n,"ReactClass: You're attempting to use a component class or function as a mixin. Instead, just use a regular object."),u(!e(n),"ReactClass: You're attempting to use a component as a mixin. Instead, just use a regular object.");var r=t.prototype,i=r.__reactAutoBindPairs;n.hasOwnProperty(s)&&g.mixins(t,n.mixins);for(var a in n)if(n.hasOwnProperty(a)&&a!==s){var c=n[a],l=r.hasOwnProperty(a);if(o(l,a),g.hasOwnProperty(a))g[a](t,c);else{var f=b.hasOwnProperty(a),y="function"==typeof c,h=y&&!f&&!l&&!1!==n.autobind;if(h)i.push(a,c),r[a]=c;else if(l){var m=b[a];u(f&&("DEFINE_MANY_MERGED"===m||"DEFINE_MANY"===m),"ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.",m,a),"DEFINE_MANY_MERGED"===m?r[a]=p(r[a],c):"DEFINE_MANY"===m&&(r[a]=d(r[a],c))}else r[a]=c}}}else;}function l(t,e){if(e)for(var n in e){var r=e[n];if(e.hasOwnProperty(n)){var o=n in g;u(!o,'ReactClass: You are attempting to define a reserved property, `%s`, that shouldn\'t be on the "statics" key. Define it as an instance property instead; it will still be accessible on the constructor.',n);var i=n in t;u(!i,"ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",n),t[n]=r}}}function f(t,e){u(t&&e&&"object"==typeof t&&"object"==typeof e,"mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.");for(var n in e)e.hasOwnProperty(n)&&(u(void 0===t[n],"mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.",n),t[n]=e[n]);return t}function p(t,e){return function(){var n=t.apply(this,arguments),r=e.apply(this,arguments);if(null==n)return r;if(null==r)return n;var o={};return f(o,n),f(o,r),o}}function d(t,e){return function(){t.apply(this,arguments),e.apply(this,arguments)}}function y(t,e){var n=e.bind(t);return n}function h(t){for(var e=t.__reactAutoBindPairs,n=0;n<e.length;n+=2){var r=e[n],o=e[n+1];t[r]=y(t,o)}}function m(t){var e=r(function(t,r,o){this.__reactAutoBindPairs.length&&h(this),this.props=t,this.context=r,this.refs=a,this.updater=o||n,this.state=null;var i=this.getInitialState?this.getInitialState():null;u("object"==typeof i&&!Array.isArray(i),"%s.getInitialState(): must return an object or null",e.displayName||"ReactCompositeComponent"),this.state=i});e.prototype=new P,e.prototype.constructor=e,e.prototype.__reactAutoBindPairs=[],v.forEach(c.bind(null,e)),c(e,E),c(e,t),c(e,x),e.getDefaultProps&&(e.defaultProps=e.getDefaultProps()),u(e.prototype.render,"createClass(...): Class specification must implement a `render` method.");for(var o in b)e.prototype[o]||(e.prototype[o]=null);return e}var v=[],b={mixins:"DEFINE_MANY",statics:"DEFINE_MANY",propTypes:"DEFINE_MANY",contextTypes:"DEFINE_MANY",childContextTypes:"DEFINE_MANY",getDefaultProps:"DEFINE_MANY_MERGED",getInitialState:"DEFINE_MANY_MERGED",getChildContext:"DEFINE_MANY_MERGED",render:"DEFINE_ONCE",componentWillMount:"DEFINE_MANY",componentDidMount:"DEFINE_MANY",componentWillReceiveProps:"DEFINE_MANY",shouldComponentUpdate:"DEFINE_ONCE",componentWillUpdate:"DEFINE_MANY",componentDidUpdate:"DEFINE_MANY",componentWillUnmount:"DEFINE_MANY",updateComponent:"OVERRIDE_BASE"},g={displayName:function(t,e){t.displayName=e},mixins:function(t,e){if(e)for(var n=0;n<e.length;n++)c(t,e[n])},childContextTypes:function(t,e){t.childContextTypes=i({},t.childContextTypes,e)},contextTypes:function(t,e){t.contextTypes=i({},t.contextTypes,e)},getDefaultProps:function(t,e){t.getDefaultProps?t.getDefaultProps=p(t.getDefaultProps,e):t.getDefaultProps=e},propTypes:function(t,e){t.propTypes=i({},t.propTypes,e)},statics:function(t,e){l(t,e)},autobind:function(){}},E={componentDidMount:function(){this.__isMounted=!0}},x={componentWillUnmount:function(){this.__isMounted=!1}},_={replaceState:function(t,e){this.updater.enqueueReplaceState(this,t,e)},isMounted:function(){return!!this.__isMounted}},P=function(){};return i(P.prototype,t.prototype,_),m}var i=t(26),a=t(23),u=t(24),s="mixins";e.exports=o},{23:23,24:24,25:25,26:26}],22:[function(t,e,n){"use strict";function r(t){return function(){return t}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(t){return t},e.exports=o},{}],23:[function(t,e,n){"use strict";var r={};e.exports=r},{}],24:[function(t,e,n){"use strict";function r(t,e,n,r,i,a,u,s){if(o(e),!t){var c;if(void 0===e)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,i,a,u,s],f=0;c=new Error(e.replace(/%s/g,function(){return l[f++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(t){};e.exports=r},{}],25:[function(t,e,n){"use strict";var r=t(22),o=r;e.exports=o},{22:22}],26:[function(t,e,n){"use strict";function r(t){if(null===t||void 0===t)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}var o=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de","5"===Object.getOwnPropertyNames(t)[0])return!1;for(var e={},n=0;n<10;n++)e["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(e).map(function(t){return e[t]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(t){r[t]=t}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(t){return!1}}()?Object.assign:function(t,e){for(var n,u,s=r(t),c=1;c<arguments.length;c++){n=Object(arguments[c]);for(var l in n)i.call(n,l)&&(s[l]=n[l]);if(o){u=o(n);for(var f=0;f<u.length;f++)a.call(n,u[f])&&(s[u[f]]=n[u[f]])}}return s}},{}],27:[function(t,e,n){"use strict";function r(t,e,n,r,o){}e.exports=r},{24:24,25:25,30:30}],28:[function(t,e,n){"use strict";var r=t(29);e.exports=function(t){return r(t,!1)}},{29:29}],29:[function(t,e,n){"use strict";var r=t(22),o=t(24),i=t(25),a=t(30),u=t(27);e.exports=function(t,e){function n(t){var e=t&&(w&&t[w]||t[N]);if("function"==typeof e)return e}function s(t,e){return t===e?0!==t||1/t==1/e:t!==t&&e!==e}function c(t){this.message=t,this.stack=""}function l(t){function n(n,r,i,u,s,l,f){if(u=u||A,l=l||i,f!==a)if(e)o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types");else;return null==r[i]?n?new c(null===r[i]?"The "+s+" `"+l+"` is marked as required in `"+u+"`, but its value is `null`.":"The "+s+" `"+l+"` is marked as required in `"+u+"`, but its value is `undefined`."):null:t(r,i,u,s,l)}var r=n.bind(null,!1);return r.isRequired=n.bind(null,!0),r}function f(t){function e(e,n,r,o,i,a){var u=e[n];if(E(u)!==t)return new c("Invalid "+o+" `"+i+"` of type `"+x(u)+"` supplied to `"+r+"`, expected `"+t+"`.");return null}return l(e)}function p(t){function e(e,n,r,o,i){if("function"!=typeof t)return new c("Property `"+i+"` of component `"+r+"` has invalid PropType notation inside arrayOf.");var u=e[n];if(!Array.isArray(u)){return new c("Invalid "+o+" `"+i+"` of type `"+E(u)+"` supplied to `"+r+"`, expected an array.")}for(var s=0;s<u.length;s++){var l=t(u,s,r,o,i+"["+s+"]",a);if(l instanceof Error)return l}return null}return l(e)}function d(t){function e(e,n,r,o,i){if(!(e[n]instanceof t)){var a=t.name||A;return new c("Invalid "+o+" `"+i+"` of type `"+P(e[n])+"` supplied to `"+r+"`, expected instance of `"+a+"`.")}return null}return l(e)}function y(t){function e(e,n,r,o,i){for(var a=e[n],u=0;u<t.length;u++)if(s(a,t[u]))return null;return new c("Invalid "+o+" `"+i+"` of value `"+a+"` supplied to `"+r+"`, expected one of "+JSON.stringify(t)+".")}return Array.isArray(t)?l(e):r.thatReturnsNull}function h(t){function e(e,n,r,o,i){if("function"!=typeof t)return new c("Property `"+i+"` of component `"+r+"` has invalid PropType notation inside objectOf.");var u=e[n],s=E(u);if("object"!==s)return new c("Invalid "+o+" `"+i+"` of type `"+s+"` supplied to `"+r+"`, expected an object.");for(var l in u)if(u.hasOwnProperty(l)){var f=t(u,l,r,o,i+"."+l,a);if(f instanceof Error)return f}return null}return l(e)}function m(t){function e(e,n,r,o,i){for(var u=0;u<t.length;u++){if(null==(0,t[u])(e,n,r,o,i,a))return null}return new c("Invalid "+o+" `"+i+"` supplied to `"+r+"`.")}if(!Array.isArray(t))return r.thatReturnsNull;for(var n=0;n<t.length;n++){var o=t[n];if("function"!=typeof o)return i(!1,"Invalid argument supplid to oneOfType. Expected an array of check functions, but received %s at index %s.",_(o),n),r.thatReturnsNull}return l(e)}function v(t){function e(e,n,r,o,i){var u=e[n],s=E(u);if("object"!==s)return new c("Invalid "+o+" `"+i+"` of type `"+s+"` supplied to `"+r+"`, expected `object`.");for(var l in t){var f=t[l];if(f){var p=f(u,l,r,o,i+"."+l,a);if(p)return p}}return null}return l(e)}function b(e){switch(typeof e){case"number":case"string":case"undefined":return!0;case"boolean":return!e;case"object":if(Array.isArray(e))return e.every(b);if(null===e||t(e))return!0;var r=n(e);if(!r)return!1;var o,i=r.call(e);if(r!==e.entries){for(;!(o=i.next()).done;)if(!b(o.value))return!1}else for(;!(o=i.next()).done;){var a=o.value;if(a&&!b(a[1]))return!1}return!0;default:return!1}}function g(t,e){return"symbol"===t||("Symbol"===e["@@toStringTag"]||"function"==typeof Symbol&&e instanceof Symbol)}function E(t){var e=typeof t;return Array.isArray(t)?"array":t instanceof RegExp?"object":g(e,t)?"symbol":e}function x(t){if(void 0===t||null===t)return""+t;var e=E(t);if("object"===e){if(t instanceof Date)return"date";if(t instanceof RegExp)return"regexp"}return e}function _(t){var e=x(t);switch(e){case"array":case"object":return"an "+e;case"boolean":case"date":case"regexp":return"a "+e;default:return e}}function P(t){return t.constructor&&t.constructor.name?t.constructor.name:A}var w="function"==typeof Symbol&&Symbol.iterator,N="@@iterator",A="<<anonymous>>",O={array:f("array"),bool:f("boolean"),func:f("function"),number:f("number"),object:f("object"),string:f("string"),symbol:f("symbol"),any:function(){return l(r.thatReturnsNull)}(),arrayOf:p,element:function(){function e(e,n,r,o,i){var a=e[n];if(!t(a)){return new c("Invalid "+o+" `"+i+"` of type `"+E(a)+"` supplied to `"+r+"`, expected a single ReactElement.")}return null}return l(e)}(),instanceOf:d,node:function(){function t(t,e,n,r,o){return b(t[e])?null:new c("Invalid "+r+" `"+o+"` supplied to `"+n+"`, expected a ReactNode.")}return l(t)}(),objectOf:h,oneOf:y,oneOfType:m,shape:v};return c.prototype=Error.prototype,O.checkPropTypes=u,O.PropTypes=O,O}},{22:22,24:24,25:25,27:27,30:30}],30:[function(t,e,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}]},{},[12])(12)});

    __LiteMolReact = __module__.exports;
})();


/**
 * ReactDOM v15.6.1
 *
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 */

/*

BSD License

For React software

Copyright (c) 2013-present, Facebook, 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 Facebook 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.

*/

var __LiteMolReactDOM;
(function () {
    var exports = {};
    var __module__ = {};

    // REPLACE require("react") by __LiteMolReact
!function(e){if("object"==typeof exports&&"undefined"!=typeof __module__)__module__.exports=e(__LiteMolReact);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.ReactDOM=e(t.React)}}(function(e){return function(t){return function(){return function e(t,n,r){function o(a,s){if(!n[a]){if(!t[a]){var u=void 0;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var l=new Error("Cannot find __module__ '"+a+"'");throw l.code="__module___NOT_FOUND",l}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){var n=t[a][1][e];return o(n||e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var i=void 0,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(e,t,n){"use strict";var r={Properties:{"aria-current":0,"aria-details":0,"aria-disabled":0,"aria-hidden":0,"aria-invalid":0,"aria-keyshortcuts":0,"aria-label":0,"aria-roledescription":0,"aria-autocomplete":0,"aria-checked":0,"aria-expanded":0,"aria-haspopup":0,"aria-level":0,"aria-modal":0,"aria-multiline":0,"aria-multiselectable":0,"aria-orientation":0,"aria-placeholder":0,"aria-pressed":0,"aria-readonly":0,"aria-required":0,"aria-selected":0,"aria-sort":0,"aria-valuemax":0,"aria-valuemin":0,"aria-valuenow":0,"aria-valuetext":0,"aria-atomic":0,"aria-busy":0,"aria-live":0,"aria-relevant":0,"aria-dropeffect":0,"aria-grabbed":0,"aria-activedescendant":0,"aria-colcount":0,"aria-colindex":0,"aria-colspan":0,"aria-controls":0,"aria-describedby":0,"aria-errormessage":0,"aria-flowto":0,"aria-labelledby":0,"aria-owns":0,"aria-posinset":0,"aria-rowcount":0,"aria-rowindex":0,"aria-rowspan":0,"aria-setsize":0},DOMAttributeNames:{},DOMPropertyNames:{}};t.exports=r},{}],2:[function(e,t,n){"use strict";var r=e(33),o=e(132),i={focusDOMComponent:function(){o(r.getNodeFromInstance(this))}};t.exports=i},{132:132,33:33}],3:[function(e,t,n){"use strict";function r(e){return(e.ctrlKey||e.altKey||e.metaKey)&&!(e.ctrlKey&&e.altKey)}function o(e){switch(e){case"topCompositionStart":return T.compositionStart;case"topCompositionEnd":return T.compositionEnd;case"topCompositionUpdate":return T.compositionUpdate}}function i(e,t){return"topKeyDown"===e&&t.keyCode===y}function a(e,t){switch(e){case"topKeyUp":return-1!==g.indexOf(t.keyCode);case"topKeyDown":return t.keyCode!==y;case"topKeyPress":case"topMouseDown":case"topBlur":return!0;default:return!1}}function s(e){var t=e.detail;return"object"==typeof t&&"data"in t?t.data:null}function u(e,t,n,r){var u,l;if(_?u=o(e):P?a(e,n)&&(u=T.compositionEnd):i(e,n)&&(u=T.compositionStart),!u)return null;E&&(P||u!==T.compositionStart?u===T.compositionEnd&&P&&(l=P.getData()):P=h.getPooled(r));var c=m.getPooled(u,t,n,r);if(l)c.data=l;else{var p=s(n);null!==p&&(c.data=p)}return d.accumulateTwoPhaseDispatches(c),c}function l(e,t){switch(e){case"topCompositionEnd":return s(t);case"topKeyPress":return t.which!==x?null:(k=!0,w);case"topTextInput":var n=t.data;return n===w&&k?null:n;default:return null}}function c(e,t){if(P){if("topCompositionEnd"===e||!_&&a(e,t)){var n=P.getData();return h.release(P),P=null,n}return null}switch(e){case"topPaste":return null;case"topKeyPress":return t.which&&!r(t)?String.fromCharCode(t.which):null;case"topCompositionEnd":return E?null:t.data;default:return null}}function p(e,t,n,r){var o;if(!(o=b?l(e,n):c(e,n)))return null;var i=v.getPooled(T.beforeInput,t,n,r);return i.data=o,d.accumulateTwoPhaseDispatches(i),i}var d=e(19),f=e(124),h=e(20),m=e(78),v=e(82),g=[9,13,27,32],y=229,_=f.canUseDOM&&"CompositionEvent"in window,C=null;f.canUseDOM&&"documentMode"in document&&(C=document.documentMode);var b=f.canUseDOM&&"TextEvent"in window&&!C&&!function(){var e=window.opera;return"object"==typeof e&&"function"==typeof e.version&&parseInt(e.version(),10)<=12}(),E=f.canUseDOM&&(!_||C&&C>8&&C<=11),x=32,w=String.fromCharCode(x),T={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["topCompositionEnd","topKeyPress","topTextInput","topPaste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:["topBlur","topCompositionEnd","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:["topBlur","topCompositionStart","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:["topBlur","topCompositionUpdate","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]}},k=!1,P=null,S={eventTypes:T,extractEvents:function(e,t,n,r){return[u(e,t,n,r),p(e,t,n,r)]}};t.exports=S},{124:124,19:19,20:20,78:78,82:82}],4:[function(e,t,n){"use strict";function r(e,t){return e+t.charAt(0).toUpperCase()+t.substring(1)}var o={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},i=["Webkit","ms","Moz","O"];Object.keys(o).forEach(function(e){i.forEach(function(t){o[r(t,e)]=o[e]})});var a={background:{backgroundAttachment:!0,backgroundColor:!0,backgroundImage:!0,backgroundPositionX:!0,backgroundPositionY:!0,backgroundRepeat:!0},backgroundPosition:{backgroundPositionX:!0,backgroundPositionY:!0},border:{borderWidth:!0,borderStyle:!0,borderColor:!0},borderBottom:{borderBottomWidth:!0,borderBottomStyle:!0,borderBottomColor:!0},borderLeft:{borderLeftWidth:!0,borderLeftStyle:!0,borderLeftColor:!0},borderRight:{borderRightWidth:!0,borderRightStyle:!0,borderRightColor:!0},borderTop:{borderTopWidth:!0,borderTopStyle:!0,borderTopColor:!0},font:{fontStyle:!0,fontVariant:!0,fontWeight:!0,fontSize:!0,lineHeight:!0,fontFamily:!0},outline:{outlineWidth:!0,outlineStyle:!0,outlineColor:!0}},s={isUnitlessNumber:o,shorthandPropertyExpansions:a};t.exports=s},{}],5:[function(e,t,n){"use strict";var r=e(4),o=e(124),i=(e(58),e(126),e(94)),a=e(137),s=e(141),u=(e(143),s(function(e){return a(e)})),l=!1,c="cssFloat";if(o.canUseDOM){var p=document.createElement("div").style;try{p.font=""}catch(e){l=!0}void 0===document.documentElement.style.cssFloat&&(c="styleFloat")}var d={createMarkupForStyles:function(e,t){var n="";for(var r in e)if(e.hasOwnProperty(r)){var o=0===r.indexOf("--"),a=e[r];null!=a&&(n+=u(r)+":",n+=i(r,a,t,o)+";")}return n||null},setValueForStyles:function(e,t,n){var o=e.style;for(var a in t)if(t.hasOwnProperty(a)){var s=0===a.indexOf("--"),u=i(a,t[a],n,s);if("float"!==a&&"cssFloat"!==a||(a=c),s)o.setProperty(a,u);else if(u)o[a]=u;else{var p=l&&r.shorthandPropertyExpansions[a];if(p)for(var d in p)o[d]="";else o[a]=""}}}};t.exports=d},{124:124,126:126,137:137,141:141,143:143,4:4,58:58,94:94}],6:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=e(113),i=e(24),a=(e(138),function(){function e(t){r(this,e),this._callbacks=null,this._contexts=null,this._arg=t}return e.prototype.enqueue=function(e,t){this._callbacks=this._callbacks||[],this._callbacks.push(e),this._contexts=this._contexts||[],this._contexts.push(t)},e.prototype.notifyAll=function(){var e=this._callbacks,t=this._contexts,n=this._arg;if(e&&t){e.length!==t.length&&o("24"),this._callbacks=null,this._contexts=null;for(var r=0;r<e.length;r++)e[r].call(t[r],n);e.length=0,t.length=0}},e.prototype.checkpoint=function(){return this._callbacks?this._callbacks.length:0},e.prototype.rollback=function(e){this._callbacks&&this._contexts&&(this._callbacks.length=e,this._contexts.length=e)},e.prototype.reset=function(){this._callbacks=null,this._contexts=null},e.prototype.destructor=function(){this.reset()},e}());t.exports=i.addPoolingTo(a)},{113:113,138:138,24:24}],7:[function(e,t,n){"use strict";function r(e,t,n){var r=k.getPooled(I.change,e,t,n);return r.type="change",E.accumulateTwoPhaseDispatches(r),r}function o(e){var t=e.nodeName&&e.nodeName.toLowerCase();return"select"===t||"input"===t&&"file"===e.type}function i(e){var t=r(R,e,S(e));T.batchedUpdates(a,t)}function a(e){b.enqueueEvents(e),b.processEventQueue(!1)}function s(e,t){O=e,R=t,O.attachEvent("onchange",i)}function u(){O&&(O.detachEvent("onchange",i),O=null,R=null)}function l(e,t){var n=P.updateValueIfChanged(e),r=!0===t.simulated&&L._allowSimulatedPassThrough;if(n||r)return e}function c(e,t){if("topChange"===e)return t}function p(e,t,n){"topFocus"===e?(u(),s(t,n)):"topBlur"===e&&u()}function d(e,t){O=e,R=t,O.attachEvent("onpropertychange",h)}function f(){O&&(O.detachEvent("onpropertychange",h),O=null,R=null)}function h(e){"value"===e.propertyName&&l(R,e)&&i(e)}function m(e,t,n){"topFocus"===e?(f(),d(t,n)):"topBlur"===e&&f()}function v(e,t,n){if("topSelectionChange"===e||"topKeyUp"===e||"topKeyDown"===e)return l(R,n)}function g(e){var t=e.nodeName;return t&&"input"===t.toLowerCase()&&("checkbox"===e.type||"radio"===e.type)}function y(e,t,n){if("topClick"===e)return l(t,n)}function _(e,t,n){if("topInput"===e||"topChange"===e)return l(t,n)}function C(e,t){if(null!=e){var n=e._wrapperState||t._wrapperState;if(n&&n.controlled&&"number"===t.type){var r=""+t.value;t.getAttribute("value")!==r&&t.setAttribute("value",r)}}}var b=e(16),E=e(19),x=e(124),w=e(33),T=e(71),k=e(80),P=e(108),S=e(102),N=e(110),M=e(111),I={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:["topBlur","topChange","topClick","topFocus","topInput","topKeyDown","topKeyUp","topSelectionChange"]}},O=null,R=null,A=!1;x.canUseDOM&&(A=N("change")&&(!document.documentMode||document.documentMode>8));var D=!1;x.canUseDOM&&(D=N("input")&&(!("documentMode"in document)||document.documentMode>9));var L={eventTypes:I,_allowSimulatedPassThrough:!0,_isInputEventSupported:D,extractEvents:function(e,t,n,i){var a,s,u=t?w.getNodeFromInstance(t):window;if(o(u)?A?a=c:s=p:M(u)?D?a=_:(a=v,s=m):g(u)&&(a=y),a){var l=a(e,t,n);if(l)return r(l,n,i)}s&&s(e,u,t),"topBlur"===e&&C(t,u)}};t.exports=L},{102:102,108:108,110:110,111:111,124:124,16:16,19:19,33:33,71:71,80:80}],8:[function(e,t,n){"use strict";function r(e,t){return Array.isArray(t)&&(t=t[1]),t?t.nextSibling:e.firstChild}function o(e,t,n){c.insertTreeBefore(e,t,n)}function i(e,t,n){Array.isArray(t)?s(e,t[0],t[1],n):m(e,t,n)}function a(e,t){if(Array.isArray(t)){var n=t[1];t=t[0],u(e,t,n),e.removeChild(n)}e.removeChild(t)}function s(e,t,n,r){for(var o=t;;){var i=o.nextSibling;if(m(e,o,r),o===n)break;o=i}}function u(e,t,n){for(;;){var r=t.nextSibling;if(r===n)break;e.removeChild(r)}}function l(e,t,n){var r=e.parentNode,o=e.nextSibling;o===t?n&&m(r,document.createTextNode(n),o):n?(h(o,n),u(r,o,t)):u(r,e,t)}var c=e(9),p=e(13),d=(e(33),e(58),e(93)),f=e(115),h=e(116),m=d(function(e,t,n){e.insertBefore(t,n)}),v=p.dangerouslyReplaceNodeWithMarkup,g={dangerouslyReplaceNodeWithMarkup:v,replaceDelimitedText:l,processUpdates:function(e,t){for(var n=0;n<t.length;n++){var s=t[n];switch(s.type){case"INSERT_MARKUP":o(e,s.content,r(e,s.afterNode));break;case"MOVE_EXISTING":i(e,s.fromNode,r(e,s.afterNode));break;case"SET_MARKUP":f(e,s.content);break;case"TEXT_CONTENT":h(e,s.content);break;case"REMOVE_NODE":a(e,s.fromNode)}}}};t.exports=g},{115:115,116:116,13:13,33:33,58:58,9:9,93:93}],9:[function(e,t,n){"use strict";function r(e){if(h){var t=e.node,n=e.children;if(n.length)for(var r=0;r<n.length;r++)m(t,n[r],null);else null!=e.html?p(t,e.html):null!=e.text&&f(t,e.text)}}function o(e,t){e.parentNode.replaceChild(t.node,e),r(t)}function i(e,t){h?e.children.push(t):e.node.appendChild(t.node)}function a(e,t){h?e.html=t:p(e.node,t)}function s(e,t){h?e.text=t:f(e.node,t)}function u(){return this.node.nodeName}function l(e){return{node:e,children:[],html:null,text:null,toString:u}}var c=e(10),p=e(115),d=e(93),f=e(116),h="undefined"!=typeof document&&"number"==typeof document.documentMode||"undefined"!=typeof navigator&&"string"==typeof navigator.userAgent&&/\bEdge\/\d/.test(navigator.userAgent),m=d(function(e,t,n){11===t.node.nodeType||1===t.node.nodeType&&"object"===t.node.nodeName.toLowerCase()&&(null==t.node.namespaceURI||t.node.namespaceURI===c.html)?(r(t),e.insertBefore(t.node,n)):(e.insertBefore(t.node,n),r(t))});l.insertTreeBefore=m,l.replaceChildWithTree=o,l.queueChild=i,l.queueHTML=a,l.queueText=s,t.exports=l},{10:10,115:115,116:116,93:93}],10:[function(e,t,n){"use strict";var r={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};t.exports=r},{}],11:[function(e,t,n){"use strict";function r(e,t){return(e&t)===t}var o=e(113),i=(e(138),{MUST_USE_PROPERTY:1,HAS_BOOLEAN_VALUE:4,HAS_NUMERIC_VALUE:8,HAS_POSITIVE_NUMERIC_VALUE:24,HAS_OVERLOADED_BOOLEAN_VALUE:32,injectDOMPropertyConfig:function(e){var t=i,n=e.Properties||{},a=e.DOMAttributeNamespaces||{},u=e.DOMAttributeNames||{},l=e.DOMPropertyNames||{},c=e.DOMMutationMethods||{};e.isCustomAttribute&&s._isCustomAttributeFunctions.push(e.isCustomAttribute);for(var p in n){s.properties.hasOwnProperty(p)&&o("48",p);var d=p.toLowerCase(),f=n[p],h={attributeName:d,attributeNamespace:null,propertyName:p,mutationMethod:null,mustUseProperty:r(f,t.MUST_USE_PROPERTY),hasBooleanValue:r(f,t.HAS_BOOLEAN_VALUE),hasNumericValue:r(f,t.HAS_NUMERIC_VALUE),hasPositiveNumericValue:r(f,t.HAS_POSITIVE_NUMERIC_VALUE),hasOverloadedBooleanValue:r(f,t.HAS_OVERLOADED_BOOLEAN_VALUE)};if(h.hasBooleanValue+h.hasNumericValue+h.hasOverloadedBooleanValue<=1||o("50",p),u.hasOwnProperty(p)){var m=u[p];h.attributeName=m}a.hasOwnProperty(p)&&(h.attributeNamespace=a[p]),l.hasOwnProperty(p)&&(h.propertyName=l[p]),c.hasOwnProperty(p)&&(h.mutationMethod=c[p]),s.properties[p]=h}}}),a=":A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",s={ID_ATTRIBUTE_NAME:"data-reactid",ROOT_ATTRIBUTE_NAME:"data-reactroot",ATTRIBUTE_NAME_START_CHAR:a,ATTRIBUTE_NAME_CHAR:a+"\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040",properties:{},getPossibleStandardName:null,_isCustomAttributeFunctions:[],isCustomAttribute:function(e){for(var t=0;t<s._isCustomAttributeFunctions.length;t++)if((0,s._isCustomAttributeFunctions[t])(e))return!0;return!1},injection:i};t.exports=s},{113:113,138:138}],12:[function(e,t,n){"use strict";function r(e){return!!l.hasOwnProperty(e)||!u.hasOwnProperty(e)&&(s.test(e)?(l[e]=!0,!0):(u[e]=!0,!1))}function o(e,t){return null==t||e.hasBooleanValue&&!t||e.hasNumericValue&&isNaN(t)||e.hasPositiveNumericValue&&t<1||e.hasOverloadedBooleanValue&&!1===t}var i=e(11),a=(e(33),e(58),e(112)),s=(e(143),new RegExp("^["+i.ATTRIBUTE_NAME_START_CHAR+"]["+i.ATTRIBUTE_NAME_CHAR+"]*$")),u={},l={},c={createMarkupForID:function(e){return i.ID_ATTRIBUTE_NAME+"="+a(e)},setAttributeForID:function(e,t){e.setAttribute(i.ID_ATTRIBUTE_NAME,t)},createMarkupForRoot:function(){return i.ROOT_ATTRIBUTE_NAME+'=""'},setAttributeForRoot:function(e){e.setAttribute(i.ROOT_ATTRIBUTE_NAME,"")},createMarkupForProperty:function(e,t){var n=i.properties.hasOwnProperty(e)?i.properties[e]:null;if(n){if(o(n,t))return"";var r=n.attributeName;return n.hasBooleanValue||n.hasOverloadedBooleanValue&&!0===t?r+'=""':r+"="+a(t)}return i.isCustomAttribute(e)?null==t?"":e+"="+a(t):null},createMarkupForCustomAttribute:function(e,t){return r(e)&&null!=t?e+"="+a(t):""},setValueForProperty:function(e,t,n){var r=i.properties.hasOwnProperty(t)?i.properties[t]:null;if(r){var a=r.mutationMethod;if(a)a(e,n);else{if(o(r,n))return void this.deleteValueForProperty(e,t);if(r.mustUseProperty)e[r.propertyName]=n;else{var s=r.attributeName,u=r.attributeNamespace;u?e.setAttributeNS(u,s,""+n):r.hasBooleanValue||r.hasOverloadedBooleanValue&&!0===n?e.setAttribute(s,""):e.setAttribute(s,""+n)}}}else if(i.isCustomAttribute(t))return void c.setValueForAttribute(e,t,n)},setValueForAttribute:function(e,t,n){r(t)&&(null==n?e.removeAttribute(t):e.setAttribute(t,""+n))},deleteValueForAttribute:function(e,t){e.removeAttribute(t)},deleteValueForProperty:function(e,t){var n=i.properties.hasOwnProperty(t)?i.properties[t]:null;if(n){var r=n.mutationMethod;if(r)r(e,void 0);else if(n.mustUseProperty){var o=n.propertyName;n.hasBooleanValue?e[o]=!1:e[o]=""}else e.removeAttribute(n.attributeName)}else i.isCustomAttribute(t)&&e.removeAttribute(t)}};t.exports=c},{11:11,112:112,143:143,33:33,58:58}],13:[function(e,t,n){"use strict";var r=e(113),o=e(9),i=e(124),a=e(129),s=e(130),u=(e(138),{dangerouslyReplaceNodeWithMarkup:function(e,t){if(i.canUseDOM||r("56"),t||r("57"),"HTML"===e.nodeName&&r("58"),"string"==typeof t){var n=a(t,s)[0];e.parentNode.replaceChild(n,e)}else o.replaceChildWithTree(e,t)}});t.exports=u},{113:113,124:124,129:129,130:130,138:138,9:9}],14:[function(e,t,n){"use strict";var r=["ResponderEventPlugin","SimpleEventPlugin","TapEventPlugin","EnterLeaveEventPlugin","ChangeEventPlugin","SelectEventPlugin","BeforeInputEventPlugin"];t.exports=r},{}],15:[function(e,t,n){"use strict";var r=e(19),o=e(33),i=e(84),a={mouseEnter:{registrationName:"onMouseEnter",dependencies:["topMouseOut","topMouseOver"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["topMouseOut","topMouseOver"]}},s={eventTypes:a,extractEvents:function(e,t,n,s){if("topMouseOver"===e&&(n.relatedTarget||n.fromElement))return null;if("topMouseOut"!==e&&"topMouseOver"!==e)return null;var u;if(s.window===s)u=s;else{var l=s.ownerDocument;u=l?l.defaultView||l.parentWindow:window}var c,p;if("topMouseOut"===e){c=t;var d=n.relatedTarget||n.toElement;p=d?o.getClosestInstanceFromNode(d):null}else c=null,p=t;if(c===p)return null;var f=null==c?u:o.getNodeFromInstance(c),h=null==p?u:o.getNodeFromInstance(p),m=i.getPooled(a.mouseLeave,c,n,s);m.type="mouseleave",m.target=f,m.relatedTarget=h;var v=i.getPooled(a.mouseEnter,p,n,s);return v.type="mouseenter",v.target=h,v.relatedTarget=f,r.accumulateEnterLeaveDispatches(m,v,c,p),[m,v]}};t.exports=s},{19:19,33:33,84:84}],16:[function(e,t,n){"use strict";function r(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}function o(e,t,n){switch(e){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":return!(!n.disabled||!r(t));default:return!1}}var i=e(113),a=e(17),s=e(18),u=e(50),l=e(91),c=e(98),p=(e(138),{}),d=null,f=function(e,t){e&&(s.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e))},h=function(e){return f(e,!0)},m=function(e){return f(e,!1)},v=function(e){return"."+e._rootNodeID},g={injection:{injectEventPluginOrder:a.injectEventPluginOrder,injectEventPluginsByName:a.injectEventPluginsByName},putListener:function(e,t,n){"function"!=typeof n&&i("94",t,typeof n);var r=v(e);(p[t]||(p[t]={}))[r]=n;var o=a.registrationName__module__s[t];o&&o.didPutListener&&o.didPutListener(e,t,n)},getListener:function(e,t){var n=p[t];if(o(t,e._currentElement.type,e._currentElement.props))return null;var r=v(e);return n&&n[r]},deleteListener:function(e,t){var n=a.registrationName__module__s[t];n&&n.willDeleteListener&&n.willDeleteListener(e,t);var r=p[t];r&&delete r[v(e)]},deleteAllListeners:function(e){var t=v(e);for(var n in p)if(p.hasOwnProperty(n)&&p[n][t]){var r=a.registrationName__module__s[n];r&&r.willDeleteListener&&r.willDeleteListener(e,n),delete p[n][t]}},extractEvents:function(e,t,n,r){for(var o,i=a.plugins,s=0;s<i.length;s++){var u=i[s];if(u){var c=u.extractEvents(e,t,n,r);c&&(o=l(o,c))}}return o},enqueueEvents:function(e){e&&(d=l(d,e))},processEventQueue:function(e){var t=d;d=null,e?c(t,h):c(t,m),d&&i("95"),u.rethrowCaughtError()},__purge:function(){p={}},__getListenerBank:function(){return p}};t.exports=g},{113:113,138:138,17:17,18:18,50:50,91:91,98:98}],17:[function(e,t,n){"use strict";function r(){if(s)for(var e in u){var t=u[e],n=s.indexOf(e);if(n>-1||a("96",e),!l.plugins[n]){t.extractEvents||a("97",e),l.plugins[n]=t;var r=t.eventTypes;for(var i in r)o(r[i],t,i)||a("98",i,e)}}}function o(e,t,n){l.eventNameDispatchConfigs.hasOwnProperty(n)&&a("99",n),l.eventNameDispatchConfigs[n]=e;var r=e.phasedRegistrationNames;if(r){for(var o in r)if(r.hasOwnProperty(o)){var s=r[o];i(s,t,n)}return!0}return!!e.registrationName&&(i(e.registrationName,t,n),!0)}function i(e,t,n){l.registrationName__module__s[e]&&a("100",e),l.registrationName__module__s[e]=t,l.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var a=e(113),s=(e(138),null),u={},l={plugins:[],eventNameDispatchConfigs:{},registrationName__module__s:{},registrationNameDependencies:{},possibleRegistrationNames:null,injectEventPluginOrder:function(e){s&&a("101"),s=Array.prototype.slice.call(e),r()},injectEventPluginsByName:function(e){var t=!1;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];u.hasOwnProperty(n)&&u[n]===o||(u[n]&&a("102",n),u[n]=o,t=!0)}t&&r()},getPlugin__module__ForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return l.registrationName__module__s[t.registrationName]||null;if(void 0!==t.phasedRegistrationNames){var n=t.phasedRegistrationNames;for(var r in n)if(n.hasOwnProperty(r)){var o=l.registrationName__module__s[n[r]];if(o)return o}}return null},_resetEventPlugins:function(){s=null;for(var e in u)u.hasOwnProperty(e)&&delete u[e];l.plugins.length=0;var t=l.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=l.registrationName__module__s;for(var o in r)r.hasOwnProperty(o)&&delete r[o]}};t.exports=l},{113:113,138:138}],18:[function(e,t,n){"use strict";function r(e){return"topMouseUp"===e||"topTouchEnd"===e||"topTouchCancel"===e}function o(e){return"topMouseMove"===e||"topTouchMove"===e}function i(e){return"topMouseDown"===e||"topTouchStart"===e}function a(e,t,n,r){var o=e.type||"unknown-event";e.currentTarget=g.getNodeFromInstance(r),t?m.invokeGuardedCallbackWithCatch(o,n,e):m.invokeGuardedCallback(o,n,e),e.currentTarget=null}function s(e,t){var n=e._dispatchListeners,r=e._dispatchInstances;if(Array.isArray(n))for(var o=0;o<n.length&&!e.isPropagationStopped();o++)a(e,t,n[o],r[o]);else n&&a(e,t,n,r);e._dispatchListeners=null,e._dispatchInstances=null}function u(e){var t=e._dispatchListeners,n=e._dispatchInstances;if(Array.isArray(t)){for(var r=0;r<t.length&&!e.isPropagationStopped();r++)if(t[r](e,n[r]))return n[r]}else if(t&&t(e,n))return n;return null}function l(e){var t=u(e);return e._dispatchInstances=null,e._dispatchListeners=null,t}function c(e){var t=e._dispatchListeners,n=e._dispatchInstances;Array.isArray(t)&&h("103"),e.currentTarget=t?g.getNodeFromInstance(n):null;var r=t?t(e):null;return e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,r}function p(e){return!!e._dispatchListeners}var d,f,h=e(113),m=e(50),v=(e(138),e(143),{injectComponentTree:function(e){d=e},injectTreeTraversal:function(e){f=e}}),g={isEndish:r,isMoveish:o,isStartish:i,executeDirectDispatch:c,executeDispatchesInOrder:s,executeDispatchesInOrderStopAtTrue:l,hasDispatches:p,getInstanceFromNode:function(e){return d.getInstanceFromNode(e)},getNodeFromInstance:function(e){return d.getNodeFromInstance(e)},isAncestor:function(e,t){return f.isAncestor(e,t)},getLowestCommonAncestor:function(e,t){return f.getLowestCommonAncestor(e,t)},getParentInstance:function(e){return f.getParentInstance(e)},traverseTwoPhase:function(e,t,n){return f.traverseTwoPhase(e,t,n)},traverseEnterLeave:function(e,t,n,r,o){return f.traverseEnterLeave(e,t,n,r,o)},injection:v};t.exports=g},{113:113,138:138,143:143,50:50}],19:[function(e,t,n){"use strict";function r(e,t,n){var r=t.dispatchConfig.phasedRegistrationNames[n];return g(e,r)}function o(e,t,n){var o=r(e,n,t);o&&(n._dispatchListeners=m(n._dispatchListeners,o),n._dispatchInstances=m(n._dispatchInstances,e))}function i(e){e&&e.dispatchConfig.phasedRegistrationNames&&h.traverseTwoPhase(e._targetInst,o,e)}function a(e){if(e&&e.dispatchConfig.phasedRegistrationNames){var t=e._targetInst,n=t?h.getParentInstance(t):null;h.traverseTwoPhase(n,o,e)}}function s(e,t,n){if(n&&n.dispatchConfig.registrationName){var r=n.dispatchConfig.registrationName,o=g(e,r);o&&(n._dispatchListeners=m(n._dispatchListeners,o),n._dispatchInstances=m(n._dispatchInstances,e))}}function u(e){e&&e.dispatchConfig.registrationName&&s(e._targetInst,null,e)}function l(e){v(e,i)}function c(e){v(e,a)}function p(e,t,n,r){h.traverseEnterLeave(n,r,s,e,t)}function d(e){v(e,u)}var f=e(16),h=e(18),m=e(91),v=e(98),g=(e(143),f.getListener),y={accumulateTwoPhaseDispatches:l,accumulateTwoPhaseDispatchesSkipTarget:c,accumulateDirectDispatches:d,accumulateEnterLeaveDispatches:p};t.exports=y},{143:143,16:16,18:18,91:91,98:98}],20:[function(e,t,n){"use strict";function r(e){this._root=e,this._startText=this.getText(),this._fallbackText=null}var o=e(144),i=e(24),a=e(106);o(r.prototype,{destructor:function(){this._root=null,this._startText=null,this._fallbackText=null},getText:function(){return"value"in this._root?this._root.value:this._root[a()]},getData:function(){if(this._fallbackText)return this._fallbackText;var e,t,n=this._startText,r=n.length,o=this.getText(),i=o.length;for(e=0;e<r&&n[e]===o[e];e++);var a=r-e;for(t=1;t<=a&&n[r-t]===o[i-t];t++);var s=t>1?1-t:void 0;return this._fallbackText=o.slice(e,s),this._fallbackText}}),i.addPoolingTo(r),t.exports=r},{106:106,144:144,24:24}],21:[function(e,t,n){"use strict";var r=e(11),o=r.injection.MUST_USE_PROPERTY,i=r.injection.HAS_BOOLEAN_VALUE,a=r.injection.HAS_NUMERIC_VALUE,s=r.injection.HAS_POSITIVE_NUMERIC_VALUE,u=r.injection.HAS_OVERLOADED_BOOLEAN_VALUE,l={isCustomAttribute:RegExp.prototype.test.bind(new RegExp("^(data|aria)-["+r.ATTRIBUTE_NAME_CHAR+"]*$")),Properties:{accept:0,acceptCharset:0,accessKey:0,action:0,allowFullScreen:i,allowTransparency:0,alt:0,as:0,async:i,autoComplete:0,autoPlay:i,capture:i,cellPadding:0,cellSpacing:0,charSet:0,challenge:0,checked:o|i,cite:0,classID:0,className:0,cols:s,colSpan:0,content:0,contentEditable:0,contextMenu:0,controls:i,coords:0,crossOrigin:0,data:0,dateTime:0,default:i,defer:i,dir:0,disabled:i,download:u,draggable:0,encType:0,form:0,formAction:0,formEncType:0,formMethod:0,formNoValidate:i,formTarget:0,frameBorder:0,headers:0,height:0,hidden:i,high:0,href:0,hrefLang:0,htmlFor:0,httpEquiv:0,icon:0,id:0,inputMode:0,integrity:0,is:0,keyParams:0,keyType:0,kind:0,label:0,lang:0,list:0,loop:i,low:0,manifest:0,marginHeight:0,marginWidth:0,max:0,maxLength:0,media:0,mediaGroup:0,method:0,min:0,minLength:0,multiple:o|i,muted:o|i,name:0,nonce:0,noValidate:i,open:i,optimum:0,pattern:0,placeholder:0,playsInline:i,poster:0,preload:0,profile:0,radioGroup:0,readOnly:i,referrerPolicy:0,rel:0,required:i,reversed:i,role:0,rows:s,rowSpan:a,sandbox:0,scope:0,scoped:i,scrolling:0,seamless:i,selected:o|i,shape:0,size:s,sizes:0,span:s,spellCheck:0,src:0,srcDoc:0,srcLang:0,srcSet:0,start:a,step:0,style:0,summary:0,tabIndex:0,target:0,title:0,type:0,useMap:0,value:0,width:0,wmode:0,wrap:0,about:0,datatype:0,inlist:0,prefix:0,property:0,resource:0,typeof:0,vocab:0,autoCapitalize:0,autoCorrect:0,autoSave:0,color:0,itemProp:0,itemScope:i,itemType:0,itemID:0,itemRef:0,results:0,security:0,unselectable:0},DOMAttributeNames:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{},DOMMutationMethods:{value:function(e,t){if(null==t)return e.removeAttribute("value");"number"!==e.type||!1===e.hasAttribute("value")?e.setAttribute("value",""+t):e.validity&&!e.validity.badInput&&e.ownerDocument.activeElement!==e&&e.setAttribute("value",""+t)}}};t.exports=l},{11:11}],22:[function(e,t,n){"use strict";function r(e){var t={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,function(e){return t[e]})}function o(e){var t=/(=0|=2)/g,n={"=0":"=","=2":":"};return(""+("."===e[0]&&"$"===e[1]?e.substring(2):e.substring(1))).replace(t,function(e){return n[e]})}var i={escape:r,unescape:o};t.exports=i},{}],23:[function(e,t,n){"use strict";function r(e){null!=e.checkedLink&&null!=e.valueLink&&s("87")}function o(e){r(e),(null!=e.value||null!=e.onChange)&&s("88")}function i(e){r(e),(null!=e.checked||null!=e.onChange)&&s("89")}function a(e){if(e){var t=e.getName();if(t)return" Check the render method of `"+t+"`."}return""}var s=e(113),u=e(64),l=e(146),c=e(121),p=l(c.isValidElement),d=(e(138),e(143),{button:!0,checkbox:!0,image:!0,hidden:!0,radio:!0,reset:!0,submit:!0}),f={value:function(e,t,n){return!e[t]||d[e.type]||e.onChange||e.readOnly||e.disabled?null:new Error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.")},checked:function(e,t,n){return!e[t]||e.onChange||e.readOnly||e.disabled?null:new Error("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.")},onChange:p.func},h={},m={checkPropTypes:function(e,t,n){for(var r in f){if(f.hasOwnProperty(r))var o=f[r](t,r,e,"prop",null,u);o instanceof Error&&!(o.message in h)&&(h[o.message]=!0,a(n))}},getValue:function(e){return e.valueLink?(o(e),e.valueLink.value):e.value},getChecked:function(e){return e.checkedLink?(i(e),e.checkedLink.value):e.checked},executeOnChange:function(e,t){return e.valueLink?(o(e),e.valueLink.requestChange(t.target.value)):e.checkedLink?(i(e),e.checkedLink.requestChange(t.target.checked)):e.onChange?e.onChange.call(void 0,t):void 0}};t.exports=m},{113:113,121:121,138:138,143:143,146:146,64:64}],24:[function(e,t,n){"use strict";var r=e(113),o=(e(138),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),i=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,e,t,n),o}return new r(e,t,n)},s=function(e,t,n,r){var o=this;if(o.instancePool.length){var i=o.instancePool.pop();return o.call(i,e,t,n,r),i}return new o(e,t,n,r)},u=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length<t.poolSize&&t.instancePool.push(e)},l=o,c=function(e,t){var n=e;return n.instancePool=[],n.getPooled=t||l,n.poolSize||(n.poolSize=10),n.release=u,n},p={addPoolingTo:c,oneArgumentPooler:o,twoArgumentPooler:i,threeArgumentPooler:a,fourArgumentPooler:s};t.exports=p},{113:113,138:138}],25:[function(e,t,n){"use strict";function r(e){return Object.prototype.hasOwnProperty.call(e,m)||(e[m]=f++,p[e[m]]={}),p[e[m]]}var o,i=e(144),a=e(17),s=e(51),u=e(90),l=e(107),c=e(110),p={},d=!1,f=0,h={topAbort:"abort",topAnimationEnd:l("animationend")||"animationend",topAnimationIteration:l("animationiteration")||"animationiteration",topAnimationStart:l("animationstart")||"animationstart",topBlur:"blur",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topChange:"change",topClick:"click",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy",topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topFocus:"focus",topInput:"input",
topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topScroll:"scroll",topSeeked:"seeked",topSeeking:"seeking",topSelectionChange:"selectionchange",topStalled:"stalled",topSuspend:"suspend",topTextInput:"textInput",topTimeUpdate:"timeupdate",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove",topTouchStart:"touchstart",topTransitionEnd:l("transitionend")||"transitionend",topVolumeChange:"volumechange",topWaiting:"waiting",topWheel:"wheel"},m="_reactListenersID"+String(Math.random()).slice(2),v=i({},s,{ReactEventListener:null,injection:{injectReactEventListener:function(e){e.setHandleTopLevel(v.handleTopLevel),v.ReactEventListener=e}},setEnabled:function(e){v.ReactEventListener&&v.ReactEventListener.setEnabled(e)},isEnabled:function(){return!(!v.ReactEventListener||!v.ReactEventListener.isEnabled())},listenTo:function(e,t){for(var n=t,o=r(n),i=a.registrationNameDependencies[e],s=0;s<i.length;s++){var u=i[s];o.hasOwnProperty(u)&&o[u]||("topWheel"===u?c("wheel")?v.ReactEventListener.trapBubbledEvent("topWheel","wheel",n):c("mousewheel")?v.ReactEventListener.trapBubbledEvent("topWheel","mousewheel",n):v.ReactEventListener.trapBubbledEvent("topWheel","DOMMouseScroll",n):"topScroll"===u?c("scroll",!0)?v.ReactEventListener.trapCapturedEvent("topScroll","scroll",n):v.ReactEventListener.trapBubbledEvent("topScroll","scroll",v.ReactEventListener.WINDOW_HANDLE):"topFocus"===u||"topBlur"===u?(c("focus",!0)?(v.ReactEventListener.trapCapturedEvent("topFocus","focus",n),v.ReactEventListener.trapCapturedEvent("topBlur","blur",n)):c("focusin")&&(v.ReactEventListener.trapBubbledEvent("topFocus","focusin",n),v.ReactEventListener.trapBubbledEvent("topBlur","focusout",n)),o.topBlur=!0,o.topFocus=!0):h.hasOwnProperty(u)&&v.ReactEventListener.trapBubbledEvent(u,h[u],n),o[u]=!0)}},trapBubbledEvent:function(e,t,n){return v.ReactEventListener.trapBubbledEvent(e,t,n)},trapCapturedEvent:function(e,t,n){return v.ReactEventListener.trapCapturedEvent(e,t,n)},supportsEventPageXY:function(){if(!document.createEvent)return!1;var e=document.createEvent("MouseEvent");return null!=e&&"pageX"in e},ensureScrollValueMonitoring:function(){if(void 0===o&&(o=v.supportsEventPageXY()),!o&&!d){var e=u.refreshScrollValues;v.ReactEventListener.monitorScrollValue(e),d=!0}}});t.exports=v},{107:107,110:110,144:144,17:17,51:51,90:90}],26:[function(e,t,n){(function(n){"use strict";function r(e,t,n,r){var o=void 0===e[n];null!=t&&o&&(e[n]=i(t,!0))}var o=e(66),i=e(109),a=(e(22),e(117)),s=e(118);e(143);void 0!==n&&n.env;var u={instantiateChildren:function(e,t,n,o){if(null==e)return null;var i={};return s(e,r,i),i},updateChildren:function(e,t,n,r,s,u,l,c,p){if(t||e){var d,f;for(d in t)if(t.hasOwnProperty(d)){f=e&&e[d];var h=f&&f._currentElement,m=t[d];if(null!=f&&a(h,m))o.receiveComponent(f,m,s,c),t[d]=f;else{f&&(r[d]=o.getHostNode(f),o.unmountComponent(f,!1));var v=i(m,!0);t[d]=v;var g=o.mountComponent(v,s,u,l,c,p);n.push(g)}}for(d in e)!e.hasOwnProperty(d)||t&&t.hasOwnProperty(d)||(f=e[d],r[d]=o.getHostNode(f),o.unmountComponent(f,!1))}},unmountChildren:function(e,t){for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];o.unmountComponent(r,t)}}};t.exports=u}).call(this,void 0)},{109:109,117:117,118:118,143:143,22:22,66:66}],27:[function(e,t,n){"use strict";var r=e(8),o=e(37),i={processChildrenUpdates:o.dangerouslyProcessChildrenUpdates,replaceNodeWithMarkup:r.dangerouslyReplaceNodeWithMarkup};t.exports=i},{37:37,8:8}],28:[function(e,t,n){"use strict";var r=e(113),o=(e(138),!1),i={replaceNodeWithMarkup:null,processChildrenUpdates:null,injection:{injectEnvironment:function(e){o&&r("104"),i.replaceNodeWithMarkup=e.replaceNodeWithMarkup,i.processChildrenUpdates=e.processChildrenUpdates,o=!0}}};t.exports=i},{113:113,138:138}],29:[function(e,t,n){"use strict";function r(e){}function o(e){return!(!e.prototype||!e.prototype.isReactComponent)}function i(e){return!(!e.prototype||!e.prototype.isPureReactComponent)}var a=e(113),s=e(144),u=e(121),l=e(28),c=e(120),p=e(50),d=e(57),f=(e(58),e(62)),h=e(66),m=e(131),v=(e(138),e(142)),g=e(117),y=(e(143),{ImpureClass:0,PureClass:1,StatelessFunctional:2});r.prototype.render=function(){var e=d.get(this)._currentElement.type,t=e(this.props,this.context,this.updater);return t};var _=1,C={construct:function(e){this._currentElement=e,this._rootNodeID=0,this._compositeType=null,this._instance=null,this._hostParent=null,this._hostContainerInfo=null,this._updateBatchNumber=null,this._pendingElement=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._renderedNodeType=null,this._renderedComponent=null,this._context=null,this._mountOrder=0,this._topLevelWrapper=null,this._pendingCallbacks=null,this._calledComponentWillUnmount=!1},mountComponent:function(e,t,n,s){this._context=s,this._mountOrder=_++,this._hostParent=t,this._hostContainerInfo=n;var l,c=this._currentElement.props,p=this._processContext(s),f=this._currentElement.type,h=e.getUpdateQueue(),v=o(f),g=this._constructComponent(v,c,p,h);v||null!=g&&null!=g.render?i(f)?this._compositeType=y.PureClass:this._compositeType=y.ImpureClass:(l=g,null===g||!1===g||u.isValidElement(g)||a("105",f.displayName||f.name||"Component"),g=new r(f),this._compositeType=y.StatelessFunctional),g.props=c,g.context=p,g.refs=m,g.updater=h,this._instance=g,d.set(g,this);var C=g.state;void 0===C&&(g.state=C=null),("object"!=typeof C||Array.isArray(C))&&a("106",this.getName()||"ReactCompositeComponent"),this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1;var b;return b=g.unstable_handleError?this.performInitialMountWithErrorHandling(l,t,n,e,s):this.performInitialMount(l,t,n,e,s),g.componentDidMount&&e.getReactMountReady().enqueue(g.componentDidMount,g),b},_constructComponent:function(e,t,n,r){return this._constructComponentWithoutOwner(e,t,n,r)},_constructComponentWithoutOwner:function(e,t,n,r){var o=this._currentElement.type;return e?new o(t,n,r):o(t,n,r)},performInitialMountWithErrorHandling:function(e,t,n,r,o){var i,a=r.checkpoint();try{i=this.performInitialMount(e,t,n,r,o)}catch(s){r.rollback(a),this._instance.unstable_handleError(s),this._pendingStateQueue&&(this._instance.state=this._processPendingState(this._instance.props,this._instance.context)),a=r.checkpoint(),this._renderedComponent.unmountComponent(!0),r.rollback(a),i=this.performInitialMount(e,t,n,r,o)}return i},performInitialMount:function(e,t,n,r,o){var i=this._instance;i.componentWillMount&&(i.componentWillMount(),this._pendingStateQueue&&(i.state=this._processPendingState(i.props,i.context))),void 0===e&&(e=this._renderValidatedComponent());var a=f.getType(e);this._renderedNodeType=a;var s=this._instantiateReactComponent(e,a!==f.EMPTY);return this._renderedComponent=s,h.mountComponent(s,r,t,n,this._processChildContext(o),0)},getHostNode:function(){return h.getHostNode(this._renderedComponent)},unmountComponent:function(e){if(this._renderedComponent){var t=this._instance;if(t.componentWillUnmount&&!t._calledComponentWillUnmount)if(t._calledComponentWillUnmount=!0,e){var n=this.getName()+".componentWillUnmount()";p.invokeGuardedCallback(n,t.componentWillUnmount.bind(t))}else t.componentWillUnmount();this._renderedComponent&&(h.unmountComponent(this._renderedComponent,e),this._renderedNodeType=null,this._renderedComponent=null,this._instance=null),this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._pendingCallbacks=null,this._pendingElement=null,this._context=null,this._rootNodeID=0,this._topLevelWrapper=null,d.remove(t)}},_maskContext:function(e){var t=this._currentElement.type,n=t.contextTypes;if(!n)return m;var r={};for(var o in n)r[o]=e[o];return r},_processContext:function(e){return this._maskContext(e)},_processChildContext:function(e){var t,n=this._currentElement.type,r=this._instance;if(r.getChildContext&&(t=r.getChildContext()),t){"object"!=typeof n.childContextTypes&&a("107",this.getName()||"ReactCompositeComponent");for(var o in t)o in n.childContextTypes||a("108",this.getName()||"ReactCompositeComponent",o);return s({},e,t)}return e},_checkContextTypes:function(e,t,n){},receiveComponent:function(e,t,n){var r=this._currentElement,o=this._context;this._pendingElement=null,this.updateComponent(t,r,e,o,n)},performUpdateIfNecessary:function(e){null!=this._pendingElement?h.receiveComponent(this,this._pendingElement,e,this._context):null!==this._pendingStateQueue||this._pendingForceUpdate?this.updateComponent(e,this._currentElement,this._currentElement,this._context,this._context):this._updateBatchNumber=null},updateComponent:function(e,t,n,r,o){var i=this._instance;null==i&&a("136",this.getName()||"ReactCompositeComponent");var s,u=!1;this._context===o?s=i.context:(s=this._processContext(o),u=!0);var l=t.props,c=n.props;t!==n&&(u=!0),u&&i.componentWillReceiveProps&&i.componentWillReceiveProps(c,s);var p=this._processPendingState(c,s),d=!0;this._pendingForceUpdate||(i.shouldComponentUpdate?d=i.shouldComponentUpdate(c,p,s):this._compositeType===y.PureClass&&(d=!v(l,c)||!v(i.state,p))),this._updateBatchNumber=null,d?(this._pendingForceUpdate=!1,this._performComponentUpdate(n,c,p,s,e,o)):(this._currentElement=n,this._context=o,i.props=c,i.state=p,i.context=s)},_processPendingState:function(e,t){var n=this._instance,r=this._pendingStateQueue,o=this._pendingReplaceState;if(this._pendingReplaceState=!1,this._pendingStateQueue=null,!r)return n.state;if(o&&1===r.length)return r[0];for(var i=s({},o?r[0]:n.state),a=o?1:0;a<r.length;a++){var u=r[a];s(i,"function"==typeof u?u.call(n,i,e,t):u)}return i},_performComponentUpdate:function(e,t,n,r,o,i){var a,s,u,l=this._instance,c=Boolean(l.componentDidUpdate);c&&(a=l.props,s=l.state,u=l.context),l.componentWillUpdate&&l.componentWillUpdate(t,n,r),this._currentElement=e,this._context=i,l.props=t,l.state=n,l.context=r,this._updateRenderedComponent(o,i),c&&o.getReactMountReady().enqueue(l.componentDidUpdate.bind(l,a,s,u),l)},_updateRenderedComponent:function(e,t){var n=this._renderedComponent,r=n._currentElement,o=this._renderValidatedComponent();if(g(r,o))h.receiveComponent(n,o,e,this._processChildContext(t));else{var i=h.getHostNode(n);h.unmountComponent(n,!1);var a=f.getType(o);this._renderedNodeType=a;var s=this._instantiateReactComponent(o,a!==f.EMPTY);this._renderedComponent=s;var u=h.mountComponent(s,e,this._hostParent,this._hostContainerInfo,this._processChildContext(t),0);this._replaceNodeWithMarkup(i,u,n)}},_replaceNodeWithMarkup:function(e,t,n){l.replaceNodeWithMarkup(e,t,n)},_renderValidatedComponentWithoutOwnerOrContext:function(){return this._instance.render()},_renderValidatedComponent:function(){var e;if(this._compositeType!==y.StatelessFunctional){c.current=this;try{e=this._renderValidatedComponentWithoutOwnerOrContext()}finally{c.current=null}}else e=this._renderValidatedComponentWithoutOwnerOrContext();return null===e||!1===e||u.isValidElement(e)||a("109",this.getName()||"ReactCompositeComponent"),e},attachRef:function(e,t){var n=this.getPublicInstance();null==n&&a("110");var r=t.getPublicInstance();(n.refs===m?n.refs={}:n.refs)[e]=r},detachRef:function(e){delete this.getPublicInstance().refs[e]},getName:function(){var e=this._currentElement.type,t=this._instance&&this._instance.constructor;return e.displayName||t&&t.displayName||e.name||t&&t.name||null},getPublicInstance:function(){var e=this._instance;return this._compositeType===y.StatelessFunctional?null:e},_instantiateReactComponent:null};t.exports=C},{113:113,117:117,120:120,121:121,131:131,138:138,142:142,143:143,144:144,28:28,50:50,57:57,58:58,62:62,66:66}],30:[function(e,t,n){"use strict";var r=e(33),o=e(47),i=e(60),a=e(66),s=e(71),u=e(72),l=e(96),c=e(103),p=e(114);e(143);o.inject();var d={findDOMNode:l,render:i.render,unmountComponentAtNode:i.unmountComponentAtNode,version:u,unstable_batchedUpdates:s.batchedUpdates,unstable_renderSubtreeIntoContainer:p};"undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject&&__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ComponentTree:{getClosestInstanceFromNode:r.getClosestInstanceFromNode,getNodeFromInstance:function(e){return e._renderedComponent&&(e=c(e)),e?r.getNodeFromInstance(e):null}},Mount:i,Reconciler:a});t.exports=d},{103:103,114:114,143:143,33:33,47:47,60:60,66:66,71:71,72:72,96:96}],31:[function(e,t,n){"use strict";function r(e){if(e){var t=e._currentElement._owner||null;if(t){var n=t.getName();if(n)return" This DOM node was rendered by `"+n+"`."}}return""}function o(e,t){t&&(Q[e._tag]&&(null!=t.children||null!=t.dangerouslySetInnerHTML)&&v("137",e._tag,e._currentElement._owner?" Check the render method of "+e._currentElement._owner.getName()+".":""),null!=t.dangerouslySetInnerHTML&&(null!=t.children&&v("60"),"object"==typeof t.dangerouslySetInnerHTML&&H in t.dangerouslySetInnerHTML||v("61")),null!=t.style&&"object"!=typeof t.style&&v("62",r(e)))}function i(e,t,n,r){if(!(r instanceof A)){var o=e._hostContainerInfo,i=o._node&&o._node.nodeType===K,s=i?o._node:o._ownerDocument;j(t,s),r.getReactMountReady().enqueue(a,{inst:e,registrationName:t,listener:n})}}function a(){var e=this;w.putListener(e.inst,e.registrationName,e.listener)}function s(){var e=this;N.postMountWrapper(e)}function u(){var e=this;O.postMountWrapper(e)}function l(){var e=this;M.postMountWrapper(e)}function c(){L.track(this)}function p(){var e=this;e._rootNodeID||v("63");var t=V(e);switch(t||v("64"),e._tag){case"iframe":case"object":e._wrapperState.listeners=[k.trapBubbledEvent("topLoad","load",t)];break;case"video":case"audio":e._wrapperState.listeners=[];for(var n in z)z.hasOwnProperty(n)&&e._wrapperState.listeners.push(k.trapBubbledEvent(n,z[n],t));break;case"source":e._wrapperState.listeners=[k.trapBubbledEvent("topError","error",t)];break;case"img":e._wrapperState.listeners=[k.trapBubbledEvent("topError","error",t),k.trapBubbledEvent("topLoad","load",t)];break;case"form":e._wrapperState.listeners=[k.trapBubbledEvent("topReset","reset",t),k.trapBubbledEvent("topSubmit","submit",t)];break;case"input":case"select":case"textarea":e._wrapperState.listeners=[k.trapBubbledEvent("topInvalid","invalid",t)]}}function d(){I.postUpdateWrapper(this)}function f(e){Z.call($,e)||(G.test(e)||v("65",e),$[e]=!0)}function h(e,t){return e.indexOf("-")>=0||null!=t.is}function m(e){var t=e.type;f(t),this._currentElement=e,this._tag=t.toLowerCase(),this._namespaceURI=null,this._renderedChildren=null,this._previousStyle=null,this._previousStyleCopy=null,this._hostNode=null,this._hostParent=null,this._rootNodeID=0,this._domID=0,this._hostContainerInfo=null,this._wrapperState=null,this._topLevelWrapper=null,this._flags=0}var v=e(113),g=e(144),y=e(2),_=e(5),C=e(9),b=e(10),E=e(11),x=e(12),w=e(16),T=e(17),k=e(25),P=e(32),S=e(33),N=e(38),M=e(39),I=e(40),O=e(43),R=(e(58),e(61)),A=e(68),D=(e(130),e(95)),L=(e(138),e(110),e(142),e(108)),U=(e(119),e(143),P),F=w.deleteListener,V=S.getNodeFromInstance,j=k.listenTo,B=T.registrationName__module__s,W={string:!0,number:!0},H="__html",q={children:null,dangerouslySetInnerHTML:null,suppressContentEditableWarning:null},K=11,z={topAbort:"abort",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topSeeked:"seeked",topSeeking:"seeking",topStalled:"stalled",topSuspend:"suspend",topTimeUpdate:"timeupdate",topVolumeChange:"volumechange",topWaiting:"waiting"},Y={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},X={listing:!0,pre:!0,textarea:!0},Q=g({menuitem:!0},Y),G=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,$={},Z={}.hasOwnProperty,J=1;m.displayName="ReactDOMComponent",m.Mixin={mountComponent:function(e,t,n,r){this._rootNodeID=J++,this._domID=n._idCounter++,this._hostParent=t,this._hostContainerInfo=n;var i=this._currentElement.props;switch(this._tag){case"audio":case"form":case"iframe":case"img":case"link":case"object":case"source":case"video":this._wrapperState={listeners:null},e.getReactMountReady().enqueue(p,this);break;case"input":N.mountWrapper(this,i,t),i=N.getHostProps(this,i),e.getReactMountReady().enqueue(c,this),e.getReactMountReady().enqueue(p,this);break;case"option":M.mountWrapper(this,i,t),i=M.getHostProps(this,i);break;case"select":I.mountWrapper(this,i,t),i=I.getHostProps(this,i),e.getReactMountReady().enqueue(p,this);break;case"textarea":O.mountWrapper(this,i,t),i=O.getHostProps(this,i),e.getReactMountReady().enqueue(c,this),e.getReactMountReady().enqueue(p,this)}o(this,i);var a,d;null!=t?(a=t._namespaceURI,d=t._tag):n._tag&&(a=n._namespaceURI,d=n._tag),(null==a||a===b.svg&&"foreignobject"===d)&&(a=b.html),a===b.html&&("svg"===this._tag?a=b.svg:"math"===this._tag&&(a=b.mathml)),this._namespaceURI=a;var f;if(e.useCreateElement){var h,m=n._ownerDocument;if(a===b.html)if("script"===this._tag){var v=m.createElement("div"),g=this._currentElement.type;v.innerHTML="<"+g+"></"+g+">",h=v.removeChild(v.firstChild)}else h=i.is?m.createElement(this._currentElement.type,i.is):m.createElement(this._currentElement.type);else h=m.createElementNS(a,this._currentElement.type);S.precacheNode(this,h),this._flags|=U.hasCachedChildNodes,this._hostParent||x.setAttributeForRoot(h),this._updateDOMProperties(null,i,e);var _=C(h);this._createInitialChildren(e,i,r,_),f=_}else{var E=this._createOpenTagMarkupAndPutListeners(e,i),w=this._createContentMarkup(e,i,r);f=!w&&Y[this._tag]?E+"/>":E+">"+w+"</"+this._currentElement.type+">"}switch(this._tag){case"input":e.getReactMountReady().enqueue(s,this),i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"textarea":e.getReactMountReady().enqueue(u,this),i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"select":case"button":i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"option":e.getReactMountReady().enqueue(l,this)}return f},_createOpenTagMarkupAndPutListeners:function(e,t){var n="<"+this._currentElement.type;for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];if(null!=o)if(B.hasOwnProperty(r))o&&i(this,r,o,e);else{"style"===r&&(o&&(o=this._previousStyleCopy=g({},t.style)),o=_.createMarkupForStyles(o,this));var a=null;null!=this._tag&&h(this._tag,t)?q.hasOwnProperty(r)||(a=x.createMarkupForCustomAttribute(r,o)):a=x.createMarkupForProperty(r,o),a&&(n+=" "+a)}}return e.renderToStaticMarkup?n:(this._hostParent||(n+=" "+x.createMarkupForRoot()),n+=" "+x.createMarkupForID(this._domID))},_createContentMarkup:function(e,t,n){var r="",o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&(r=o.__html);else{var i=W[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)r=D(i);else if(null!=a){var s=this.mountChildren(a,e,n);r=s.join("")}}return X[this._tag]&&"\n"===r.charAt(0)?"\n"+r:r},_createInitialChildren:function(e,t,n,r){var o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&C.queueHTML(r,o.__html);else{var i=W[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)""!==i&&C.queueText(r,i);else if(null!=a)for(var s=this.mountChildren(a,e,n),u=0;u<s.length;u++)C.queueChild(r,s[u])}},receiveComponent:function(e,t,n){var r=this._currentElement;this._currentElement=e,this.updateComponent(t,r,e,n)},updateComponent:function(e,t,n,r){var i=t.props,a=this._currentElement.props;switch(this._tag){case"input":i=N.getHostProps(this,i),a=N.getHostProps(this,a);break;case"option":i=M.getHostProps(this,i),a=M.getHostProps(this,a);break;case"select":i=I.getHostProps(this,i),a=I.getHostProps(this,a);break;case"textarea":i=O.getHostProps(this,i),a=O.getHostProps(this,a)}switch(o(this,a),this._updateDOMProperties(i,a,e),this._updateDOMChildren(i,a,e,r),this._tag){case"input":N.updateWrapper(this);break;case"textarea":O.updateWrapper(this);break;case"select":e.getReactMountReady().enqueue(d,this)}},_updateDOMProperties:function(e,t,n){var r,o,a;for(r in e)if(!t.hasOwnProperty(r)&&e.hasOwnProperty(r)&&null!=e[r])if("style"===r){var s=this._previousStyleCopy;for(o in s)s.hasOwnProperty(o)&&(a=a||{},a[o]="");this._previousStyleCopy=null}else B.hasOwnProperty(r)?e[r]&&F(this,r):h(this._tag,e)?q.hasOwnProperty(r)||x.deleteValueForAttribute(V(this),r):(E.properties[r]||E.isCustomAttribute(r))&&x.deleteValueForProperty(V(this),r);for(r in t){var u=t[r],l="style"===r?this._previousStyleCopy:null!=e?e[r]:void 0;if(t.hasOwnProperty(r)&&u!==l&&(null!=u||null!=l))if("style"===r)if(u?u=this._previousStyleCopy=g({},u):this._previousStyleCopy=null,l){for(o in l)!l.hasOwnProperty(o)||u&&u.hasOwnProperty(o)||(a=a||{},a[o]="");for(o in u)u.hasOwnProperty(o)&&l[o]!==u[o]&&(a=a||{},a[o]=u[o])}else a=u;else if(B.hasOwnProperty(r))u?i(this,r,u,n):l&&F(this,r);else if(h(this._tag,t))q.hasOwnProperty(r)||x.setValueForAttribute(V(this),r,u);else if(E.properties[r]||E.isCustomAttribute(r)){var c=V(this);null!=u?x.setValueForProperty(c,r,u):x.deleteValueForProperty(c,r)}}a&&_.setValueForStyles(V(this),a,this)},_updateDOMChildren:function(e,t,n,r){var o=W[typeof e.children]?e.children:null,i=W[typeof t.children]?t.children:null,a=e.dangerouslySetInnerHTML&&e.dangerouslySetInnerHTML.__html,s=t.dangerouslySetInnerHTML&&t.dangerouslySetInnerHTML.__html,u=null!=o?null:e.children,l=null!=i?null:t.children,c=null!=o||null!=a,p=null!=i||null!=s;null!=u&&null==l?this.updateChildren(null,n,r):c&&!p&&this.updateTextContent(""),null!=i?o!==i&&this.updateTextContent(""+i):null!=s?a!==s&&this.updateMarkup(""+s):null!=l&&this.updateChildren(l,n,r)},getHostNode:function(){return V(this)},unmountComponent:function(e){switch(this._tag){case"audio":case"form":case"iframe":case"img":case"link":case"object":case"source":case"video":var t=this._wrapperState.listeners;if(t)for(var n=0;n<t.length;n++)t[n].remove();break;case"input":case"textarea":L.stopTracking(this);break;case"html":case"head":case"body":v("66",this._tag)}this.unmountChildren(e),S.uncacheNode(this),w.deleteAllListeners(this),this._rootNodeID=0,this._domID=0,this._wrapperState=null},getPublicInstance:function(){return V(this)}},g(m.prototype,m.Mixin,R.Mixin),t.exports=m},{10:10,108:108,11:11,110:110,113:113,119:119,12:12,130:130,138:138,142:142,143:143,144:144,16:16,17:17,2:2,25:25,32:32,33:33,38:38,39:39,40:40,43:43,5:5,58:58,61:61,68:68,9:9,95:95}],32:[function(e,t,n){"use strict";var r={hasCachedChildNodes:1};t.exports=r},{}],33:[function(e,t,n){"use strict";function r(e,t){return 1===e.nodeType&&e.getAttribute(h)===String(t)||8===e.nodeType&&e.nodeValue===" react-text: "+t+" "||8===e.nodeType&&e.nodeValue===" react-empty: "+t+" "}function o(e){for(var t;t=e._renderedComponent;)e=t;return e}function i(e,t){var n=o(e);n._hostNode=t,t[v]=n}function a(e){var t=e._hostNode;t&&(delete t[v],e._hostNode=null)}function s(e,t){if(!(e._flags&m.hasCachedChildNodes)){var n=e._renderedChildren,a=t.firstChild;e:for(var s in n)if(n.hasOwnProperty(s)){var u=n[s],l=o(u)._domID;if(0!==l){for(;null!==a;a=a.nextSibling)if(r(a,l)){i(u,a);continue e}p("32",l)}}e._flags|=m.hasCachedChildNodes}}function u(e){if(e[v])return e[v];for(var t=[];!e[v];){if(t.push(e),!e.parentNode)return null;e=e.parentNode}for(var n,r;e&&(r=e[v]);e=t.pop())n=r,t.length&&s(r,e);return n}function l(e){var t=u(e);return null!=t&&t._hostNode===e?t:null}function c(e){if(void 0===e._hostNode&&p("33"),e._hostNode)return e._hostNode;for(var t=[];!e._hostNode;)t.push(e),e._hostParent||p("34"),e=e._hostParent;for(;t.length;e=t.pop())s(e,e._hostNode);return e._hostNode}var p=e(113),d=e(11),f=e(32),h=(e(138),d.ID_ATTRIBUTE_NAME),m=f,v="__reactInternalInstance$"+Math.random().toString(36).slice(2),g={getClosestInstanceFromNode:u,getInstanceFromNode:l,getNodeFromInstance:c,precacheChildNodes:s,precacheNode:i,uncacheNode:a};t.exports=g},{11:11,113:113,138:138,32:32}],34:[function(e,t,n){"use strict";function r(e,t){return{_topLevelWrapper:e,_idCounter:1,_ownerDocument:t?t.nodeType===o?t:t.ownerDocument:null,_node:t,_tag:t?t.nodeName.toLowerCase():null,_namespaceURI:t?t.namespaceURI:null}}var o=(e(119),9);t.exports=r},{119:119}],35:[function(e,t,n){"use strict";var r=e(144),o=e(9),i=e(33),a=function(e){this._currentElement=null,this._hostNode=null,this._hostParent=null,this._hostContainerInfo=null,this._domID=0};r(a.prototype,{mountComponent:function(e,t,n,r){var a=n._idCounter++;this._domID=a,this._hostParent=t,this._hostContainerInfo=n;var s=" react-empty: "+this._domID+" ";if(e.useCreateElement){var u=n._ownerDocument,l=u.createComment(s);return i.precacheNode(this,l),o(l)}return e.renderToStaticMarkup?"":"\x3c!--"+s+"--\x3e"},receiveComponent:function(){},getHostNode:function(){return i.getNodeFromInstance(this)},unmountComponent:function(){i.uncacheNode(this)}}),t.exports=a},{144:144,33:33,9:9}],36:[function(e,t,n){"use strict";var r={useCreateElement:!0,useFiber:!1};t.exports=r},{}],37:[function(e,t,n){"use strict";var r=e(8),o=e(33),i={dangerouslyProcessChildrenUpdates:function(e,t){var n=o.getNodeFromInstance(e);r.processUpdates(n,t)}};t.exports=i},{33:33,8:8}],38:[function(e,t,n){"use strict";function r(){this._rootNodeID&&d.updateWrapper(this)}function o(e){return"checkbox"===e.type||"radio"===e.type?null!=e.checked:null!=e.value}function i(e){var t=this._currentElement.props,n=l.executeOnChange(t,e);p.asap(r,this);var o=t.name;if("radio"===t.type&&null!=o){for(var i=c.getNodeFromInstance(this),s=i;s.parentNode;)s=s.parentNode;for(var u=s.querySelectorAll("input[name="+JSON.stringify(""+o)+'][type="radio"]'),d=0;d<u.length;d++){var f=u[d];if(f!==i&&f.form===i.form){var h=c.getInstanceFromNode(f);h||a("90"),p.asap(r,h)}}}return n}var a=e(113),s=e(144),u=e(12),l=e(23),c=e(33),p=e(71),d=(e(138),e(143),{getHostProps:function(e,t){var n=l.getValue(t),r=l.getChecked(t);return s({type:void 0,step:void 0,min:void 0,max:void 0},t,{defaultChecked:void 0,defaultValue:void 0,value:null!=n?n:e._wrapperState.initialValue,checked:null!=r?r:e._wrapperState.initialChecked,onChange:e._wrapperState.onChange})},mountWrapper:function(e,t){var n=t.defaultValue;e._wrapperState={initialChecked:null!=t.checked?t.checked:t.defaultChecked,initialValue:null!=t.value?t.value:n,listeners:null,onChange:i.bind(e),controlled:o(t)}},updateWrapper:function(e){var t=e._currentElement.props,n=t.checked;null!=n&&u.setValueForProperty(c.getNodeFromInstance(e),"checked",n||!1);var r=c.getNodeFromInstance(e),o=l.getValue(t);if(null!=o)if(0===o&&""===r.value)r.value="0";else if("number"===t.type){var i=parseFloat(r.value,10)||0;(o!=i||o==i&&r.value!=o)&&(r.value=""+o)}else r.value!==""+o&&(r.value=""+o);else null==t.value&&null!=t.defaultValue&&r.defaultValue!==""+t.defaultValue&&(r.defaultValue=""+t.defaultValue),null==t.checked&&null!=t.defaultChecked&&(r.defaultChecked=!!t.defaultChecked)},postMountWrapper:function(e){var t=e._currentElement.props,n=c.getNodeFromInstance(e);switch(t.type){case"submit":case"reset":break;case"color":case"date":case"datetime":case"datetime-local":case"month":case"time":case"week":n.value="",n.value=n.defaultValue;break;default:n.value=n.value}var r=n.name;""!==r&&(n.name=""),n.defaultChecked=!n.defaultChecked,n.defaultChecked=!n.defaultChecked,""!==r&&(n.name=r)}});t.exports=d},{113:113,12:12,138:138,143:143,144:144,23:23,33:33,71:71}],39:[function(e,t,n){"use strict";function r(e){var t="";return i.Children.forEach(e,function(e){null!=e&&("string"==typeof e||"number"==typeof e?t+=e:u||(u=!0))}),t}var o=e(144),i=e(121),a=e(33),s=e(40),u=(e(143),!1),l={mountWrapper:function(e,t,n){var o=null;if(null!=n){var i=n;"optgroup"===i._tag&&(i=i._hostParent),null!=i&&"select"===i._tag&&(o=s.getSelectValueContext(i))}var a=null;if(null!=o){var u;if(u=null!=t.value?t.value+"":r(t.children),a=!1,Array.isArray(o)){for(var l=0;l<o.length;l++)if(""+o[l]===u){a=!0;break}}else a=""+o===u}e._wrapperState={selected:a}},postMountWrapper:function(e){var t=e._currentElement.props;null!=t.value&&a.getNodeFromInstance(e).setAttribute("value",t.value)},getHostProps:function(e,t){var n=o({selected:void 0,children:void 0},t);null!=e._wrapperState.selected&&(n.selected=e._wrapperState.selected);var i=r(t.children);return i&&(n.children=i),n}};t.exports=l},{121:121,143:143,144:144,33:33,40:40}],40:[function(e,t,n){"use strict";function r(){if(this._rootNodeID&&this._wrapperState.pendingUpdate){this._wrapperState.pendingUpdate=!1;var e=this._currentElement.props,t=s.getValue(e);null!=t&&o(this,Boolean(e.multiple),t)}}function o(e,t,n){var r,o,i=u.getNodeFromInstance(e).options;if(t){for(r={},o=0;o<n.length;o++)r[""+n[o]]=!0;for(o=0;o<i.length;o++){var a=r.hasOwnProperty(i[o].value);i[o].selected!==a&&(i[o].selected=a)}}else{for(r=""+n,o=0;o<i.length;o++)if(i[o].value===r)return void(i[o].selected=!0);i.length&&(i[0].selected=!0)}}function i(e){var t=this._currentElement.props,n=s.executeOnChange(t,e);return this._rootNodeID&&(this._wrapperState.pendingUpdate=!0),l.asap(r,this),n}var a=e(144),s=e(23),u=e(33),l=e(71),c=(e(143),!1),p={getHostProps:function(e,t){return a({},t,{onChange:e._wrapperState.onChange,value:void 0})},mountWrapper:function(e,t){var n=s.getValue(t);e._wrapperState={pendingUpdate:!1,initialValue:null!=n?n:t.defaultValue,listeners:null,onChange:i.bind(e),wasMultiple:Boolean(t.multiple)},void 0===t.value||void 0===t.defaultValue||c||(c=!0)},getSelectValueContext:function(e){return e._wrapperState.initialValue},postUpdateWrapper:function(e){var t=e._currentElement.props;e._wrapperState.initialValue=void 0;var n=e._wrapperState.wasMultiple;e._wrapperState.wasMultiple=Boolean(t.multiple);var r=s.getValue(t);null!=r?(e._wrapperState.pendingUpdate=!1,o(e,Boolean(t.multiple),r)):n!==Boolean(t.multiple)&&(null!=t.defaultValue?o(e,Boolean(t.multiple),t.defaultValue):o(e,Boolean(t.multiple),t.multiple?[]:""))}};t.exports=p},{143:143,144:144,23:23,33:33,71:71}],41:[function(e,t,n){"use strict";function r(e,t,n,r){return e===n&&t===r}function o(e){var t=document.selection,n=t.createRange(),r=n.text.length,o=n.duplicate();o.moveToElementText(e),o.setEndPoint("EndToStart",n);var i=o.text.length;return{start:i,end:i+r}}function i(e){var t=window.getSelection&&window.getSelection();if(!t||0===t.rangeCount)return null;var n=t.anchorNode,o=t.anchorOffset,i=t.focusNode,a=t.focusOffset,s=t.getRangeAt(0);try{s.startContainer.nodeType,s.endContainer.nodeType}catch(e){return null}var u=r(t.anchorNode,t.anchorOffset,t.focusNode,t.focusOffset),l=u?0:s.toString().length,c=s.cloneRange();c.selectNodeContents(e),c.setEnd(s.startContainer,s.startOffset);var p=r(c.startContainer,c.startOffset,c.endContainer,c.endOffset),d=p?0:c.toString().length,f=d+l,h=document.createRange();h.setStart(n,o),h.setEnd(i,a);var m=h.collapsed;return{start:m?f:d,end:m?d:f}}function a(e,t){var n,r,o=document.selection.createRange().duplicate();void 0===t.end?(n=t.start,r=n):t.start>t.end?(n=t.end,r=t.start):(n=t.start,r=t.end),o.moveToElementText(e),o.moveStart("character",n),o.setEndPoint("EndToStart",o),o.moveEnd("character",r-n),o.select()}function s(e,t){if(window.getSelection){var n=window.getSelection(),r=e[c()].length,o=Math.min(t.start,r),i=void 0===t.end?o:Math.min(t.end,r);if(!n.extend&&o>i){var a=i;i=o,o=a}var s=l(e,o),u=l(e,i);if(s&&u){var p=document.createRange();p.setStart(s.node,s.offset),n.removeAllRanges(),o>i?(n.addRange(p),n.extend(u.node,u.offset)):(p.setEnd(u.node,u.offset),n.addRange(p))}}}var u=e(124),l=e(105),c=e(106),p=u.canUseDOM&&"selection"in document&&!("getSelection"in window),d={getOffsets:p?o:i,setOffsets:p?a:s};t.exports=d},{105:105,106:106,124:124}],
42:[function(e,t,n){"use strict";var r=e(113),o=e(144),i=e(8),a=e(9),s=e(33),u=e(95),l=(e(138),e(119),function(e){this._currentElement=e,this._stringText=""+e,this._hostNode=null,this._hostParent=null,this._domID=0,this._mountIndex=0,this._closingComment=null,this._commentNodes=null});o(l.prototype,{mountComponent:function(e,t,n,r){var o=n._idCounter++,i=" react-text: "+o+" ";if(this._domID=o,this._hostParent=t,e.useCreateElement){var l=n._ownerDocument,c=l.createComment(i),p=l.createComment(" /react-text "),d=a(l.createDocumentFragment());return a.queueChild(d,a(c)),this._stringText&&a.queueChild(d,a(l.createTextNode(this._stringText))),a.queueChild(d,a(p)),s.precacheNode(this,c),this._closingComment=p,d}var f=u(this._stringText);return e.renderToStaticMarkup?f:"\x3c!--"+i+"--\x3e"+f+"\x3c!-- /react-text --\x3e"},receiveComponent:function(e,t){if(e!==this._currentElement){this._currentElement=e;var n=""+e;if(n!==this._stringText){this._stringText=n;var r=this.getHostNode();i.replaceDelimitedText(r[0],r[1],n)}}},getHostNode:function(){var e=this._commentNodes;if(e)return e;if(!this._closingComment)for(var t=s.getNodeFromInstance(this),n=t.nextSibling;;){if(null==n&&r("67",this._domID),8===n.nodeType&&" /react-text "===n.nodeValue){this._closingComment=n;break}n=n.nextSibling}return e=[this._hostNode,this._closingComment],this._commentNodes=e,e},unmountComponent:function(){this._closingComment=null,this._commentNodes=null,s.uncacheNode(this)}}),t.exports=l},{113:113,119:119,138:138,144:144,33:33,8:8,9:9,95:95}],43:[function(e,t,n){"use strict";function r(){this._rootNodeID&&c.updateWrapper(this)}function o(e){var t=this._currentElement.props,n=s.executeOnChange(t,e);return l.asap(r,this),n}var i=e(113),a=e(144),s=e(23),u=e(33),l=e(71),c=(e(138),e(143),{getHostProps:function(e,t){return null!=t.dangerouslySetInnerHTML&&i("91"),a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue,onChange:e._wrapperState.onChange})},mountWrapper:function(e,t){var n=s.getValue(t),r=n;if(null==n){var a=t.defaultValue,u=t.children;null!=u&&(null!=a&&i("92"),Array.isArray(u)&&(u.length<=1||i("93"),u=u[0]),a=""+u),null==a&&(a=""),r=a}e._wrapperState={initialValue:""+r,listeners:null,onChange:o.bind(e)}},updateWrapper:function(e){var t=e._currentElement.props,n=u.getNodeFromInstance(e),r=s.getValue(t);if(null!=r){var o=""+r;o!==n.value&&(n.value=o),null==t.defaultValue&&(n.defaultValue=o)}null!=t.defaultValue&&(n.defaultValue=t.defaultValue)},postMountWrapper:function(e){var t=u.getNodeFromInstance(e),n=t.textContent;n===e._wrapperState.initialValue&&(t.value=n)}});t.exports=c},{113:113,138:138,143:143,144:144,23:23,33:33,71:71}],44:[function(e,t,n){"use strict";function r(e,t){"_hostNode"in e||u("33"),"_hostNode"in t||u("33");for(var n=0,r=e;r;r=r._hostParent)n++;for(var o=0,i=t;i;i=i._hostParent)o++;for(;n-o>0;)e=e._hostParent,n--;for(;o-n>0;)t=t._hostParent,o--;for(var a=n;a--;){if(e===t)return e;e=e._hostParent,t=t._hostParent}return null}function o(e,t){"_hostNode"in e||u("35"),"_hostNode"in t||u("35");for(;t;){if(t===e)return!0;t=t._hostParent}return!1}function i(e){return"_hostNode"in e||u("36"),e._hostParent}function a(e,t,n){for(var r=[];e;)r.push(e),e=e._hostParent;var o;for(o=r.length;o-- >0;)t(r[o],"captured",n);for(o=0;o<r.length;o++)t(r[o],"bubbled",n)}function s(e,t,n,o,i){for(var a=e&&t?r(e,t):null,s=[];e&&e!==a;)s.push(e),e=e._hostParent;for(var u=[];t&&t!==a;)u.push(t),t=t._hostParent;var l;for(l=0;l<s.length;l++)n(s[l],"bubbled",o);for(l=u.length;l-- >0;)n(u[l],"captured",i)}var u=e(113);e(138);t.exports={isAncestor:o,getLowestCommonAncestor:r,getParentInstance:i,traverseTwoPhase:a,traverseEnterLeave:s}},{113:113,138:138}],45:[function(e,t,n){"use strict";var r=e(121),o=e(30),i=o;r.addons&&(r.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=i),t.exports=i},{121:121,30:30}],46:[function(e,t,n){"use strict";function r(){this.reinitializeTransaction()}var o=e(144),i=e(71),a=e(89),s=e(130),u={initialize:s,close:function(){d.isBatchingUpdates=!1}},l={initialize:s,close:i.flushBatchedUpdates.bind(i)},c=[l,u];o(r.prototype,a,{getTransactionWrappers:function(){return c}});var p=new r,d={isBatchingUpdates:!1,batchedUpdates:function(e,t,n,r,o,i){var a=d.isBatchingUpdates;return d.isBatchingUpdates=!0,a?e(t,n,r,o,i):p.perform(e,null,t,n,r,o,i)}};t.exports=d},{130:130,144:144,71:71,89:89}],47:[function(e,t,n){"use strict";function r(){x||(x=!0,y.EventEmitter.injectReactEventListener(g),y.EventPluginHub.injectEventPluginOrder(s),y.EventPluginUtils.injectComponentTree(d),y.EventPluginUtils.injectTreeTraversal(h),y.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:E,EnterLeaveEventPlugin:u,ChangeEventPlugin:a,SelectEventPlugin:b,BeforeInputEventPlugin:i}),y.HostComponent.injectGenericComponentClass(p),y.HostComponent.injectTextComponentClass(m),y.DOMProperty.injectDOMPropertyConfig(o),y.DOMProperty.injectDOMPropertyConfig(l),y.DOMProperty.injectDOMPropertyConfig(C),y.EmptyComponent.injectEmptyComponentFactory(function(e){return new f(e)}),y.Updates.injectReconcileTransaction(_),y.Updates.injectBatchingStrategy(v),y.Component.injectEnvironment(c))}var o=e(1),i=e(3),a=e(7),s=e(14),u=e(15),l=e(21),c=e(27),p=e(31),d=e(33),f=e(35),h=e(44),m=e(42),v=e(46),g=e(52),y=e(55),_=e(65),C=e(73),b=e(74),E=e(75),x=!1;t.exports={inject:r}},{1:1,14:14,15:15,21:21,27:27,3:3,31:31,33:33,35:35,42:42,44:44,46:46,52:52,55:55,65:65,7:7,73:73,74:74,75:75}],48:[function(e,t,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;t.exports=r},{}],49:[function(e,t,n){"use strict";var r,o={injectEmptyComponentFactory:function(e){r=e}},i={create:function(e){return r(e)}};i.injection=o,t.exports=i},{}],50:[function(e,t,n){"use strict";function r(e,t,n){try{t(n)}catch(e){null===o&&(o=e)}}var o=null,i={invokeGuardedCallback:r,invokeGuardedCallbackWithCatch:r,rethrowCaughtError:function(){if(o){var e=o;throw o=null,e}}};t.exports=i},{}],51:[function(e,t,n){"use strict";function r(e){o.enqueueEvents(e),o.processEventQueue(!1)}var o=e(16),i={handleTopLevel:function(e,t,n,i){r(o.extractEvents(e,t,n,i))}};t.exports=i},{16:16}],52:[function(e,t,n){"use strict";function r(e){for(;e._hostParent;)e=e._hostParent;var t=p.getNodeFromInstance(e),n=t.parentNode;return p.getClosestInstanceFromNode(n)}function o(e,t){this.topLevelType=e,this.nativeEvent=t,this.ancestors=[]}function i(e){var t=f(e.nativeEvent),n=p.getClosestInstanceFromNode(t),o=n;do{e.ancestors.push(o),o=o&&r(o)}while(o);for(var i=0;i<e.ancestors.length;i++)n=e.ancestors[i],m._handleTopLevel(e.topLevelType,n,e.nativeEvent,f(e.nativeEvent))}function a(e){e(h(window))}var s=e(144),u=e(123),l=e(124),c=e(24),p=e(33),d=e(71),f=e(102),h=e(135);s(o.prototype,{destructor:function(){this.topLevelType=null,this.nativeEvent=null,this.ancestors.length=0}}),c.addPoolingTo(o,c.twoArgumentPooler);var m={_enabled:!0,_handleTopLevel:null,WINDOW_HANDLE:l.canUseDOM?window:null,setHandleTopLevel:function(e){m._handleTopLevel=e},setEnabled:function(e){m._enabled=!!e},isEnabled:function(){return m._enabled},trapBubbledEvent:function(e,t,n){return n?u.listen(n,t,m.dispatchEvent.bind(null,e)):null},trapCapturedEvent:function(e,t,n){return n?u.capture(n,t,m.dispatchEvent.bind(null,e)):null},monitorScrollValue:function(e){var t=a.bind(null,e);u.listen(window,"scroll",t)},dispatchEvent:function(e,t){if(m._enabled){var n=o.getPooled(e,t);try{d.batchedUpdates(i,n)}finally{o.release(n)}}}};t.exports=m},{102:102,123:123,124:124,135:135,144:144,24:24,33:33,71:71}],53:[function(e,t,n){"use strict";var r={logTopLevelRenders:!1};t.exports=r},{}],54:[function(e,t,n){"use strict";function r(e){return s||a("111",e.type),new s(e)}function o(e){return new u(e)}function i(e){return e instanceof u}var a=e(113),s=(e(138),null),u=null,l={injectGenericComponentClass:function(e){s=e},injectTextComponentClass:function(e){u=e}},c={createInternalComponent:r,createInstanceForText:o,isTextComponent:i,injection:l};t.exports=c},{113:113,138:138}],55:[function(e,t,n){"use strict";var r=e(11),o=e(16),i=e(18),a=e(28),s=e(49),u=e(25),l=e(54),c=e(71),p={Component:a.injection,DOMProperty:r.injection,EmptyComponent:s.injection,EventPluginHub:o.injection,EventPluginUtils:i.injection,EventEmitter:u.injection,HostComponent:l.injection,Updates:c.injection};t.exports=p},{11:11,16:16,18:18,25:25,28:28,49:49,54:54,71:71}],56:[function(e,t,n){"use strict";function r(e){return i(document.documentElement,e)}var o=e(41),i=e(127),a=e(132),s=e(133),u={hasSelectionCapabilities:function(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&"text"===e.type||"textarea"===t||"true"===e.contentEditable)},getSelectionInformation:function(){var e=s();return{focusedElem:e,selectionRange:u.hasSelectionCapabilities(e)?u.getSelection(e):null}},restoreSelection:function(e){var t=s(),n=e.focusedElem,o=e.selectionRange;t!==n&&r(n)&&(u.hasSelectionCapabilities(n)&&u.setSelection(n,o),a(n))},getSelection:function(e){var t;if("selectionStart"in e)t={start:e.selectionStart,end:e.selectionEnd};else if(document.selection&&e.nodeName&&"input"===e.nodeName.toLowerCase()){var n=document.selection.createRange();n.parentElement()===e&&(t={start:-n.moveStart("character",-e.value.length),end:-n.moveEnd("character",-e.value.length)})}else t=o.getOffsets(e);return t||{start:0,end:0}},setSelection:function(e,t){var n=t.start,r=t.end;if(void 0===r&&(r=n),"selectionStart"in e)e.selectionStart=n,e.selectionEnd=Math.min(r,e.value.length);else if(document.selection&&e.nodeName&&"input"===e.nodeName.toLowerCase()){var i=e.createTextRange();i.collapse(!0),i.moveStart("character",n),i.moveEnd("character",r-n),i.select()}else o.setOffsets(e,t)}};t.exports=u},{127:127,132:132,133:133,41:41}],57:[function(e,t,n){"use strict";var r={remove:function(e){e._reactInternalInstance=void 0},get:function(e){return e._reactInternalInstance},has:function(e){return void 0!==e._reactInternalInstance},set:function(e,t){e._reactInternalInstance=t}};t.exports=r},{}],58:[function(e,t,n){"use strict";t.exports={debugTool:null}},{}],59:[function(e,t,n){"use strict";var r=e(92),o=/\/?>/,i=/^<\!\-\-/,a={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(e){var t=r(e);return i.test(e)?e:e.replace(o," "+a.CHECKSUM_ATTR_NAME+'="'+t+'"$&')},canReuseMarkup:function(e,t){var n=t.getAttribute(a.CHECKSUM_ATTR_NAME);return n=n&&parseInt(n,10),r(e)===n}};t.exports=a},{92:92}],60:[function(e,t,n){"use strict";function r(e,t){for(var n=Math.min(e.length,t.length),r=0;r<n;r++)if(e.charAt(r)!==t.charAt(r))return r;return e.length===t.length?-1:n}function o(e){return e?e.nodeType===A?e.documentElement:e.firstChild:null}function i(e){return e.getAttribute&&e.getAttribute(I)||""}function a(e,t,n,r,o){var i;if(b.logTopLevelRenders){var a=e._currentElement.props.child,s=a.type;i="React mount: "+("string"==typeof s?s:s.displayName||s.name),console.time(i)}var u=w.mountComponent(e,n,null,_(e,t),o,0);i&&console.timeEnd(i),e._renderedComponent._topLevelWrapper=e,V._mountImageIntoNode(u,t,e,r,n)}function s(e,t,n,r){var o=k.ReactReconcileTransaction.getPooled(!n&&C.useCreateElement);o.perform(a,null,e,t,o,n,r),k.ReactReconcileTransaction.release(o)}function u(e,t,n){for(w.unmountComponent(e,n),t.nodeType===A&&(t=t.documentElement);t.lastChild;)t.removeChild(t.lastChild)}function l(e){var t=o(e);if(t){var n=y.getInstanceFromNode(t);return!(!n||!n._hostParent)}}function c(e){return!(!e||e.nodeType!==R&&e.nodeType!==A&&e.nodeType!==D)}function p(e){var t=o(e),n=t&&y.getInstanceFromNode(t);return n&&!n._hostParent?n:null}function d(e){var t=p(e);return t?t._hostContainerInfo._topLevelWrapper:null}var f=e(113),h=e(9),m=e(11),v=e(121),g=e(25),y=(e(120),e(33)),_=e(34),C=e(36),b=e(53),E=e(57),x=(e(58),e(59)),w=e(66),T=e(70),k=e(71),P=e(131),S=e(109),N=(e(138),e(115)),M=e(117),I=(e(143),m.ID_ATTRIBUTE_NAME),O=m.ROOT_ATTRIBUTE_NAME,R=1,A=9,D=11,L={},U=1,F=function(){this.rootID=U++};F.prototype.isReactComponent={},F.prototype.render=function(){return this.props.child},F.isReactTopLevelWrapper=!0;var V={TopLevelWrapper:F,_instancesByReactRootID:L,scrollMonitor:function(e,t){t()},_updateRootComponent:function(e,t,n,r,o){return V.scrollMonitor(r,function(){T.enqueueElementInternal(e,t,n),o&&T.enqueueCallbackInternal(e,o)}),e},_renderNewRootComponent:function(e,t,n,r){c(t)||f("37"),g.ensureScrollValueMonitoring();var o=S(e,!1);k.batchedUpdates(s,o,t,n,r);var i=o._instance.rootID;return L[i]=o,o},renderSubtreeIntoContainer:function(e,t,n,r){return null!=e&&E.has(e)||f("38"),V._renderSubtreeIntoContainer(e,t,n,r)},_renderSubtreeIntoContainer:function(e,t,n,r){T.validateCallback(r,"ReactDOM.render"),v.isValidElement(t)||f("39","string"==typeof t?" Instead of passing a string like 'div', pass React.createElement('div') or <div />.":"function"==typeof t?" Instead of passing a class like Foo, pass React.createElement(Foo) or <Foo />.":null!=t&&void 0!==t.props?" This may be caused by unintentionally loading two independent copies of React.":"");var a,s=v.createElement(F,{child:t});if(e){var u=E.get(e);a=u._processChildContext(u._context)}else a=P;var c=d(n);if(c){var p=c._currentElement,h=p.props.child;if(M(h,t)){var m=c._renderedComponent.getPublicInstance(),g=r&&function(){r.call(m)};return V._updateRootComponent(c,s,a,n,g),m}V.unmountComponentAtNode(n)}var y=o(n),_=y&&!!i(y),C=l(n),b=_&&!c&&!C,x=V._renderNewRootComponent(s,n,b,a)._renderedComponent.getPublicInstance();return r&&r.call(x),x},render:function(e,t,n){return V._renderSubtreeIntoContainer(null,e,t,n)},unmountComponentAtNode:function(e){c(e)||f("40");var t=d(e);return t?(delete L[t._instance.rootID],k.batchedUpdates(u,t,e,!1),!0):(l(e),1===e.nodeType&&e.hasAttribute(O),!1)},_mountImageIntoNode:function(e,t,n,i,a){if(c(t)||f("41"),i){var s=o(t);if(x.canReuseMarkup(e,s))return void y.precacheNode(n,s);var u=s.getAttribute(x.CHECKSUM_ATTR_NAME);s.removeAttribute(x.CHECKSUM_ATTR_NAME);var l=s.outerHTML;s.setAttribute(x.CHECKSUM_ATTR_NAME,u);var p=e,d=r(p,l),m=" (client) "+p.substring(d-20,d+20)+"\n (server) "+l.substring(d-20,d+20);t.nodeType===A&&f("42",m)}if(t.nodeType===A&&f("43"),a.useCreateElement){for(;t.lastChild;)t.removeChild(t.lastChild);h.insertTreeBefore(t,e,null)}else N(t,e),y.precacheNode(n,t.firstChild)}};t.exports=V},{109:109,11:11,113:113,115:115,117:117,120:120,121:121,131:131,138:138,143:143,25:25,33:33,34:34,36:36,53:53,57:57,58:58,59:59,66:66,70:70,71:71,9:9}],61:[function(e,t,n){"use strict";function r(e,t,n){return{type:"INSERT_MARKUP",content:e,fromIndex:null,fromNode:null,toIndex:n,afterNode:t}}function o(e,t,n){return{type:"MOVE_EXISTING",content:null,fromIndex:e._mountIndex,fromNode:d.getHostNode(e),toIndex:n,afterNode:t}}function i(e,t){return{type:"REMOVE_NODE",content:null,fromIndex:e._mountIndex,fromNode:t,toIndex:null,afterNode:null}}function a(e){return{type:"SET_MARKUP",content:e,fromIndex:null,fromNode:null,toIndex:null,afterNode:null}}function s(e){return{type:"TEXT_CONTENT",content:e,fromIndex:null,fromNode:null,toIndex:null,afterNode:null}}function u(e,t){return t&&(e=e||[],e.push(t)),e}function l(e,t){p.processChildrenUpdates(e,t)}var c=e(113),p=e(28),d=(e(57),e(58),e(120),e(66)),f=e(26),h=(e(130),e(97)),m=(e(138),{Mixin:{_reconcilerInstantiateChildren:function(e,t,n){return f.instantiateChildren(e,t,n)},_reconcilerUpdateChildren:function(e,t,n,r,o,i){var a;return a=h(t,0),f.updateChildren(e,a,n,r,o,this,this._hostContainerInfo,i,0),a},mountChildren:function(e,t,n){var r=this._reconcilerInstantiateChildren(e,t,n);this._renderedChildren=r;var o=[],i=0;for(var a in r)if(r.hasOwnProperty(a)){var s=r[a],u=d.mountComponent(s,t,this,this._hostContainerInfo,n,0);s._mountIndex=i++,o.push(u)}return o},updateTextContent:function(e){var t=this._renderedChildren;f.unmountChildren(t,!1);for(var n in t)t.hasOwnProperty(n)&&c("118");l(this,[s(e)])},updateMarkup:function(e){var t=this._renderedChildren;f.unmountChildren(t,!1);for(var n in t)t.hasOwnProperty(n)&&c("118");l(this,[a(e)])},updateChildren:function(e,t,n){this._updateChildren(e,t,n)},_updateChildren:function(e,t,n){var r=this._renderedChildren,o={},i=[],a=this._reconcilerUpdateChildren(r,e,i,o,t,n);if(a||r){var s,c=null,p=0,f=0,h=0,m=null;for(s in a)if(a.hasOwnProperty(s)){var v=r&&r[s],g=a[s];v===g?(c=u(c,this.moveChild(v,m,p,f)),f=Math.max(v._mountIndex,f),v._mountIndex=p):(v&&(f=Math.max(v._mountIndex,f)),c=u(c,this._mountChildAtIndex(g,i[h],m,p,t,n)),h++),p++,m=d.getHostNode(g)}for(s in o)o.hasOwnProperty(s)&&(c=u(c,this._unmountChild(r[s],o[s])));c&&l(this,c),this._renderedChildren=a}},unmountChildren:function(e){var t=this._renderedChildren;f.unmountChildren(t,e),this._renderedChildren=null},moveChild:function(e,t,n,r){if(e._mountIndex<r)return o(e,t,n)},createChild:function(e,t,n){return r(n,t,e._mountIndex)},removeChild:function(e,t){return i(e,t)},_mountChildAtIndex:function(e,t,n,r,o,i){return e._mountIndex=r,this.createChild(e,n,t)},_unmountChild:function(e,t){var n=this.removeChild(e,t);return e._mountIndex=null,n}}});t.exports=m},{113:113,120:120,130:130,138:138,26:26,28:28,57:57,58:58,66:66,97:97}],62:[function(e,t,n){"use strict";var r=e(113),o=e(121),i=(e(138),{HOST:0,COMPOSITE:1,EMPTY:2,getType:function(e){return null===e||!1===e?i.EMPTY:o.isValidElement(e)?"function"==typeof e.type?i.COMPOSITE:i.HOST:void r("26",e)}});t.exports=i},{113:113,121:121,138:138}],63:[function(e,t,n){"use strict";function r(e){return!(!e||"function"!=typeof e.attachRef||"function"!=typeof e.detachRef)}var o=e(113),i=(e(138),{addComponentAsRefTo:function(e,t,n){r(n)||o("119"),n.attachRef(t,e)},removeComponentAsRefFrom:function(e,t,n){r(n)||o("120");var i=n.getPublicInstance();i&&i.refs[t]===e.getPublicInstance()&&n.detachRef(t)}});t.exports=i},{113:113,138:138}],64:[function(e,t,n){"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}],65:[function(e,t,n){"use strict";function r(e){this.reinitializeTransaction(),this.renderToStaticMarkup=!1,this.reactMountReady=i.getPooled(null),this.useCreateElement=e}var o=e(144),i=e(6),a=e(24),s=e(25),u=e(56),l=(e(58),e(89)),c=e(70),p={initialize:u.getSelectionInformation,close:u.restoreSelection},d={initialize:function(){var e=s.isEnabled();return s.setEnabled(!1),e},close:function(e){s.setEnabled(e)}},f={initialize:function(){this.reactMountReady.reset()},close:function(){this.reactMountReady.notifyAll()}},h=[p,d,f],m={getTransactionWrappers:function(){return h},getReactMountReady:function(){return this.reactMountReady},getUpdateQueue:function(){return c},checkpoint:function(){return this.reactMountReady.checkpoint()},rollback:function(e){this.reactMountReady.rollback(e)},destructor:function(){i.release(this.reactMountReady),this.reactMountReady=null}};o(r.prototype,l,m),a.addPoolingTo(r),t.exports=r},{144:144,24:24,25:25,56:56,58:58,6:6,70:70,89:89}],66:[function(e,t,n){"use strict";function r(){o.attachRefs(this,this._currentElement)}var o=e(67),i=(e(58),e(143),{mountComponent:function(e,t,n,o,i,a){var s=e.mountComponent(t,n,o,i,a);return e._currentElement&&null!=e._currentElement.ref&&t.getReactMountReady().enqueue(r,e),s},getHostNode:function(e){return e.getHostNode()},unmountComponent:function(e,t){o.detachRefs(e,e._currentElement),e.unmountComponent(t)},receiveComponent:function(e,t,n,i){var a=e._currentElement;if(t!==a||i!==e._context){var s=o.shouldUpdateRefs(a,t);s&&o.detachRefs(e,a),e.receiveComponent(t,n,i),s&&e._currentElement&&null!=e._currentElement.ref&&n.getReactMountReady().enqueue(r,e)}},performUpdateIfNecessary:function(e,t,n){e._updateBatchNumber===n&&e.performUpdateIfNecessary(t)}});t.exports=i},{143:143,58:58,67:67}],67:[function(e,t,n){"use strict";function r(e,t,n){"function"==typeof e?e(t.getPublicInstance()):i.addComponentAsRefTo(t,e,n)}function o(e,t,n){"function"==typeof e?e(null):i.removeComponentAsRefFrom(t,e,n)}var i=e(63),a={};a.attachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&r(n,e,t._owner)}},a.shouldUpdateRefs=function(e,t){var n=null,r=null;null!==e&&"object"==typeof e&&(n=e.ref,r=e._owner);var o=null,i=null;return null!==t&&"object"==typeof t&&(o=t.ref,i=t._owner),n!==o||"string"==typeof o&&i!==r},a.detachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&o(n,e,t._owner)}},t.exports=a},{63:63}],68:[function(e,t,n){"use strict";function r(e){this.reinitializeTransaction(),this.renderToStaticMarkup=e,this.useCreateElement=!1,this.updateQueue=new s(this)}var o=e(144),i=e(24),a=e(89),s=(e(58),e(69)),u=[],l={enqueue:function(){}},c={getTransactionWrappers:function(){return u},getReactMountReady:function(){return l},getUpdateQueue:function(){return this.updateQueue},destructor:function(){},checkpoint:function(){},rollback:function(){}};o(r.prototype,a,c),i.addPoolingTo(r),t.exports=r},{144:144,24:24,58:58,69:69,89:89}],69:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=e(70),i=(e(143),function(){function e(t){r(this,e),this.transaction=t}return e.prototype.isMounted=function(e){return!1},e.prototype.enqueueCallback=function(e,t,n){this.transaction.isInTransaction()&&o.enqueueCallback(e,t,n)},e.prototype.enqueueForceUpdate=function(e){this.transaction.isInTransaction()&&o.enqueueForceUpdate(e)},e.prototype.enqueueReplaceState=function(e,t){this.transaction.isInTransaction()&&o.enqueueReplaceState(e,t)},e.prototype.enqueueSetState=function(e,t){this.transaction.isInTransaction()&&o.enqueueSetState(e,t)},e}());t.exports=i},{143:143,70:70}],70:[function(e,t,n){"use strict";function r(e){u.enqueueUpdate(e)}function o(e){var t=typeof e;if("object"!==t)return t;var n=e.constructor&&e.constructor.name||t,r=Object.keys(e);return r.length>0&&r.length<20?n+" (keys: "+r.join(", ")+")":n}function i(e,t){var n=s.get(e);return n||null}var a=e(113),s=(e(120),e(57)),u=(e(58),e(71)),l=(e(138),e(143),{isMounted:function(e){var t=s.get(e);return!!t&&!!t._renderedComponent},enqueueCallback:function(e,t,n){l.validateCallback(t,n);var o=i(e);if(!o)return null;o._pendingCallbacks?o._pendingCallbacks.push(t):o._pendingCallbacks=[t],r(o)},enqueueCallbackInternal:function(e,t){e._pendingCallbacks?e._pendingCallbacks.push(t):e._pendingCallbacks=[t],r(e)},enqueueForceUpdate:function(e){var t=i(e,"forceUpdate");t&&(t._pendingForceUpdate=!0,r(t))},enqueueReplaceState:function(e,t,n){var o=i(e,"replaceState");o&&(o._pendingStateQueue=[t],o._pendingReplaceState=!0,void 0!==n&&null!==n&&(l.validateCallback(n,"replaceState"),o._pendingCallbacks?o._pendingCallbacks.push(n):o._pendingCallbacks=[n]),r(o))},enqueueSetState:function(e,t){var n=i(e,"setState");n&&((n._pendingStateQueue||(n._pendingStateQueue=[])).push(t),r(n))},enqueueElementInternal:function(e,t,n){e._pendingElement=t,e._context=n,r(e)},validateCallback:function(e,t){e&&"function"!=typeof e&&a("122",t,o(e))}});t.exports=l},{113:113,120:120,138:138,143:143,57:57,58:58,71:71}],71:[function(e,t,n){"use strict";function r(){P.ReactReconcileTransaction&&b||c("123")}function o(){this.reinitializeTransaction(),this.dirtyComponentsLength=null,this.callbackQueue=d.getPooled(),this.reconcileTransaction=P.ReactReconcileTransaction.getPooled(!0)}function i(e,t,n,o,i,a){return r(),b.batchedUpdates(e,t,n,o,i,a)}function a(e,t){return e._mountOrder-t._mountOrder}function s(e){var t=e.dirtyComponentsLength;t!==g.length&&c("124",t,g.length),g.sort(a),y++;for(var n=0;n<t;n++){var r=g[n],o=r._pendingCallbacks;r._pendingCallbacks=null;var i;if(h.logTopLevelRenders){var s=r;r._currentElement.type.isReactTopLevelWrapper&&(s=r._renderedComponent),i="React update: "+s.getName(),console.time(i)}if(m.performUpdateIfNecessary(r,e.reconcileTransaction,y),i&&console.timeEnd(i),o)for(var u=0;u<o.length;u++)e.callbackQueue.enqueue(o[u],r.getPublicInstance())}}function u(e){if(r(),!b.isBatchingUpdates)return void b.batchedUpdates(u,e);g.push(e),null==e._updateBatchNumber&&(e._updateBatchNumber=y+1)}function l(e,t){b.isBatchingUpdates||c("125"),_.enqueue(e,t),C=!0}var c=e(113),p=e(144),d=e(6),f=e(24),h=e(53),m=e(66),v=e(89),g=(e(138),[]),y=0,_=d.getPooled(),C=!1,b=null,E={initialize:function(){this.dirtyComponentsLength=g.length},close:function(){this.dirtyComponentsLength!==g.length?(g.splice(0,this.dirtyComponentsLength),T()):g.length=0}},x={initialize:function(){this.callbackQueue.reset()},close:function(){this.callbackQueue.notifyAll()}},w=[E,x];p(o.prototype,v,{getTransactionWrappers:function(){return w},destructor:function(){this.dirtyComponentsLength=null,d.release(this.callbackQueue),this.callbackQueue=null,P.ReactReconcileTransaction.release(this.reconcileTransaction),this.reconcileTransaction=null},perform:function(e,t,n){return v.perform.call(this,this.reconcileTransaction.perform,this.reconcileTransaction,e,t,n)}}),f.addPoolingTo(o);var T=function(){for(;g.length||C;){if(g.length){var e=o.getPooled();e.perform(s,null,e),o.release(e)}if(C){C=!1;var t=_;_=d.getPooled(),t.notifyAll(),d.release(t)}}},k={injectReconcileTransaction:function(e){e||c("126"),P.ReactReconcileTransaction=e},injectBatchingStrategy:function(e){e||c("127"),"function"!=typeof e.batchedUpdates&&c("128"),"boolean"!=typeof e.isBatchingUpdates&&c("129"),b=e}},P={ReactReconcileTransaction:null,batchedUpdates:i,enqueueUpdate:u,flushBatchedUpdates:T,injection:k,asap:l};t.exports=P},{113:113,138:138,144:144,24:24,53:53,6:6,66:66,89:89}],72:[function(e,t,n){"use strict";t.exports="15.6.1"},{}],73:[function(e,t,n){"use strict";var r={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace"},o={accentHeight:"accent-height",accumulate:0,additive:0,alignmentBaseline:"alignment-baseline",allowReorder:"allowReorder",alphabetic:0,amplitude:0,arabicForm:"arabic-form",ascent:0,attributeName:"attributeName",attributeType:"attributeType",autoReverse:"autoReverse",azimuth:0,baseFrequency:"baseFrequency",baseProfile:"baseProfile",baselineShift:"baseline-shift",bbox:0,begin:0,bias:0,by:0,calcMode:"calcMode",capHeight:"cap-height",clip:0,clipPath:"clip-path",clipRule:"clip-rule",clipPathUnits:"clipPathUnits",colorInterpolation:"color-interpolation",colorInterpolationFilters:"color-interpolation-filters",colorProfile:"color-profile",colorRendering:"color-rendering",contentScriptType:"contentScriptType",contentStyleType:"contentStyleType",cursor:0,cx:0,cy:0,d:0,decelerate:0,descent:0,diffuseConstant:"diffuseConstant",direction:0,display:0,divisor:0,dominantBaseline:"dominant-baseline",dur:0,dx:0,dy:0,edgeMode:"edgeMode",elevation:0,enableBackground:"enable-background",end:0,exponent:0,externalResourcesRequired:"externalResourcesRequired",fill:0,fillOpacity:"fill-opacity",fillRule:"fill-rule",filter:0,filterRes:"filterRes",filterUnits:"filterUnits",floodColor:"flood-color",floodOpacity:"flood-opacity",focusable:0,fontFamily:"font-family",fontSize:"font-size",fontSizeAdjust:"font-size-adjust",fontStretch:"font-stretch",fontStyle:"font-style",fontVariant:"font-variant",fontWeight:"font-weight",format:0,from:0,fx:0,fy:0,g1:0,g2:0,glyphName:"glyph-name",glyphOrientationHorizontal:"glyph-orientation-horizontal",glyphOrientationVertical:"glyph-orientation-vertical",glyphRef:"glyphRef",gradientTransform:"gradientTransform",gradientUnits:"gradientUnits",hanging:0,horizAdvX:"horiz-adv-x",horizOriginX:"horiz-origin-x",ideographic:0,imageRendering:"image-rendering",in:0,in2:0,intercept:0,k:0,k1:0,k2:0,k3:0,k4:0,kernelMatrix:"kernelMatrix",kernelUnitLength:"kernelUnitLength",kerning:0,keyPoints:"keyPoints",keySplines:"keySplines",keyTimes:"keyTimes",lengthAdjust:"lengthAdjust",letterSpacing:"letter-spacing",lightingColor:"lighting-color",limitingConeAngle:"limitingConeAngle",local:0,markerEnd:"marker-end",markerMid:"marker-mid",markerStart:"marker-start",markerHeight:"markerHeight",markerUnits:"markerUnits",markerWidth:"markerWidth",mask:0,maskContentUnits:"maskContentUnits",maskUnits:"maskUnits",mathematical:0,mode:0,numOctaves:"numOctaves",offset:0,opacity:0,operator:0,order:0,orient:0,orientation:0,origin:0,overflow:0,overlinePosition:"overline-position",overlineThickness:"overline-thickness",paintOrder:"paint-order",panose1:"panose-1",pathLength:"pathLength",patternContentUnits:"patternContentUnits",patternTransform:"patternTransform",patternUnits:"patternUnits",pointerEvents:"pointer-events",points:0,pointsAtX:"pointsAtX",pointsAtY:"pointsAtY",pointsAtZ:"pointsAtZ",preserveAlpha:"preserveAlpha",preserveAspectRatio:"preserveAspectRatio",primitiveUnits:"primitiveUnits",r:0,radius:0,refX:"refX",refY:"refY",renderingIntent:"rendering-intent",repeatCount:"repeatCount",repeatDur:"repeatDur",requiredExtensions:"requiredExtensions",requiredFeatures:"requiredFeatures",restart:0,result:0,rotate:0,rx:0,ry:0,scale:0,seed:0,shapeRendering:"shape-rendering",slope:0,spacing:0,specularConstant:"specularConstant",specularExponent:"specularExponent",speed:0,spreadMethod:"spreadMethod",startOffset:"startOffset",stdDeviation:"stdDeviation",stemh:0,stemv:0,stitchTiles:"stitchTiles",stopColor:"stop-color",stopOpacity:"stop-opacity",strikethroughPosition:"strikethrough-position",strikethroughThickness:"strikethrough-thickness",string:0,stroke:0,strokeDasharray:"stroke-dasharray",strokeDashoffset:"stroke-dashoffset",strokeLinecap:"stroke-linecap",strokeLinejoin:"stroke-linejoin",strokeMiterlimit:"stroke-miterlimit",strokeOpacity:"stroke-opacity",strokeWidth:"stroke-width",surfaceScale:"surfaceScale",systemLanguage:"systemLanguage",tableValues:"tableValues",targetX:"targetX",targetY:"targetY",textAnchor:"text-anchor",textDecoration:"text-decoration",textRendering:"text-rendering",textLength:"textLength",to:0,transform:0,u1:0,u2:0,underlinePosition:"underline-position",underlineThickness:"underline-thickness",unicode:0,unicodeBidi:"unicode-bidi",unicodeRange:"unicode-range",unitsPerEm:"units-per-em",vAlphabetic:"v-alphabetic",vHanging:"v-hanging",vIdeographic:"v-ideographic",vMathematical:"v-mathematical",values:0,vectorEffect:"vector-effect",version:0,vertAdvY:"vert-adv-y",vertOriginX:"vert-origin-x",vertOriginY:"vert-origin-y",viewBox:"viewBox",viewTarget:"viewTarget",visibility:0,widths:0,wordSpacing:"word-spacing",writingMode:"writing-mode",x:0,xHeight:"x-height",x1:0,x2:0,xChannelSelector:"xChannelSelector",xlinkActuate:"xlink:actuate",xlinkArcrole:"xlink:arcrole",xlinkHref:"xlink:href",xlinkRole:"xlink:role",xlinkShow:"xlink:show",xlinkTitle:"xlink:title",xlinkType:"xlink:type",xmlBase:"xml:base",xmlns:0,xmlnsXlink:"xmlns:xlink",xmlLang:"xml:lang",xmlSpace:"xml:space",y:0,y1:0,y2:0,yChannelSelector:"yChannelSelector",z:0,zoomAndPan:"zoomAndPan"},i={Properties:{},DOMAttributeNamespaces:{xlinkActuate:r.xlink,xlinkArcrole:r.xlink,xlinkHref:r.xlink,xlinkRole:r.xlink,xlinkShow:r.xlink,xlinkTitle:r.xlink,xlinkType:r.xlink,xmlBase:r.xml,xmlLang:r.xml,xmlSpace:r.xml},DOMAttributeNames:{}};Object.keys(o).forEach(function(e){i.Properties[e]=0,o[e]&&(i.DOMAttributeNames[e]=o[e])}),t.exports=i},{}],74:[function(e,t,n){"use strict";function r(e){if("selectionStart"in e&&u.hasSelectionCapabilities(e))return{start:e.selectionStart,end:e.selectionEnd};if(window.getSelection){var t=window.getSelection();return{anchorNode:t.anchorNode,anchorOffset:t.anchorOffset,focusNode:t.focusNode,focusOffset:t.focusOffset}}if(document.selection){var n=document.selection.createRange();return{parentElement:n.parentElement(),text:n.text,top:n.boundingTop,left:n.boundingLeft}}}function o(e,t){if(y||null==m||m!==c())return null;var n=r(m);if(!g||!d(g,n)){g=n;var o=l.getPooled(h.select,v,e,t);return o.type="select",o.target=m,i.accumulateTwoPhaseDispatches(o),o}return null}var i=e(19),a=e(124),s=e(33),u=e(56),l=e(80),c=e(133),p=e(111),d=e(142),f=a.canUseDOM&&"documentMode"in document&&document.documentMode<=11,h={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:["topBlur","topContextMenu","topFocus","topKeyDown","topKeyUp","topMouseDown","topMouseUp","topSelectionChange"]}},m=null,v=null,g=null,y=!1,_=!1,C={eventTypes:h,
extractEvents:function(e,t,n,r){if(!_)return null;var i=t?s.getNodeFromInstance(t):window;switch(e){case"topFocus":(p(i)||"true"===i.contentEditable)&&(m=i,v=t,g=null);break;case"topBlur":m=null,v=null,g=null;break;case"topMouseDown":y=!0;break;case"topContextMenu":case"topMouseUp":return y=!1,o(n,r);case"topSelectionChange":if(f)break;case"topKeyDown":case"topKeyUp":return o(n,r)}return null},didPutListener:function(e,t,n){"onSelect"===t&&(_=!0)}};t.exports=C},{111:111,124:124,133:133,142:142,19:19,33:33,56:56,80:80}],75:[function(e,t,n){"use strict";function r(e){return"."+e._rootNodeID}function o(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}var i=e(113),a=e(123),s=e(19),u=e(33),l=e(76),c=e(77),p=e(80),d=e(81),f=e(83),h=e(84),m=e(79),v=e(85),g=e(86),y=e(87),_=e(88),C=e(130),b=e(99),E=(e(138),{}),x={};["abort","animationEnd","animationIteration","animationStart","blur","canPlay","canPlayThrough","click","contextMenu","copy","cut","doubleClick","drag","dragEnd","dragEnter","dragExit","dragLeave","dragOver","dragStart","drop","durationChange","emptied","encrypted","ended","error","focus","input","invalid","keyDown","keyPress","keyUp","load","loadedData","loadedMetadata","loadStart","mouseDown","mouseMove","mouseOut","mouseOver","mouseUp","paste","pause","play","playing","progress","rateChange","reset","scroll","seeked","seeking","stalled","submit","suspend","timeUpdate","touchCancel","touchEnd","touchMove","touchStart","transitionEnd","volumeChange","waiting","wheel"].forEach(function(e){var t=e[0].toUpperCase()+e.slice(1),n="on"+t,r="top"+t,o={phasedRegistrationNames:{bubbled:n,captured:n+"Capture"},dependencies:[r]};E[e]=o,x[r]=o});var w={},T={eventTypes:E,extractEvents:function(e,t,n,r){var o=x[e];if(!o)return null;var a;switch(e){case"topAbort":case"topCanPlay":case"topCanPlayThrough":case"topDurationChange":case"topEmptied":case"topEncrypted":case"topEnded":case"topError":case"topInput":case"topInvalid":case"topLoad":case"topLoadedData":case"topLoadedMetadata":case"topLoadStart":case"topPause":case"topPlay":case"topPlaying":case"topProgress":case"topRateChange":case"topReset":case"topSeeked":case"topSeeking":case"topStalled":case"topSubmit":case"topSuspend":case"topTimeUpdate":case"topVolumeChange":case"topWaiting":a=p;break;case"topKeyPress":if(0===b(n))return null;case"topKeyDown":case"topKeyUp":a=f;break;case"topBlur":case"topFocus":a=d;break;case"topClick":if(2===n.button)return null;case"topDoubleClick":case"topMouseDown":case"topMouseMove":case"topMouseUp":case"topMouseOut":case"topMouseOver":case"topContextMenu":a=h;break;case"topDrag":case"topDragEnd":case"topDragEnter":case"topDragExit":case"topDragLeave":case"topDragOver":case"topDragStart":case"topDrop":a=m;break;case"topTouchCancel":case"topTouchEnd":case"topTouchMove":case"topTouchStart":a=v;break;case"topAnimationEnd":case"topAnimationIteration":case"topAnimationStart":a=l;break;case"topTransitionEnd":a=g;break;case"topScroll":a=y;break;case"topWheel":a=_;break;case"topCopy":case"topCut":case"topPaste":a=c}a||i("86",e);var u=a.getPooled(o,t,n,r);return s.accumulateTwoPhaseDispatches(u),u},didPutListener:function(e,t,n){if("onClick"===t&&!o(e._tag)){var i=r(e),s=u.getNodeFromInstance(e);w[i]||(w[i]=a.listen(s,"click",C))}},willDeleteListener:function(e,t){if("onClick"===t&&!o(e._tag)){var n=r(e);w[n].remove(),delete w[n]}}};t.exports=T},{113:113,123:123,130:130,138:138,19:19,33:33,76:76,77:77,79:79,80:80,81:81,83:83,84:84,85:85,86:86,87:87,88:88,99:99}],76:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={animationName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),t.exports=r},{80:80}],77:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}};o.augmentClass(r,i),t.exports=r},{80:80}],78:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={data:null};o.augmentClass(r,i),t.exports=r},{80:80}],79:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(84),i={dataTransfer:null};o.augmentClass(r,i),t.exports=r},{84:84}],80:[function(e,t,n){"use strict";function r(e,t,n,r){this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n;var o=this.constructor.Interface;for(var i in o)if(o.hasOwnProperty(i)){var s=o[i];s?this[i]=s(n):"target"===i?this.target=r:this[i]=n[i]}var u=null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue;return this.isDefaultPrevented=u?a.thatReturnsTrue:a.thatReturnsFalse,this.isPropagationStopped=a.thatReturnsFalse,this}var o=e(144),i=e(24),a=e(130),s=(e(143),["dispatchConfig","_targetInst","nativeEvent","isDefaultPrevented","isPropagationStopped","_dispatchListeners","_dispatchInstances"]),u={type:null,target:null,currentTarget:a.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null};o(r.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=a.thatReturnsTrue)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=a.thatReturnsTrue)},persist:function(){this.isPersistent=a.thatReturnsTrue},isPersistent:a.thatReturnsFalse,destructor:function(){var e=this.constructor.Interface;for(var t in e)this[t]=null;for(var n=0;n<s.length;n++)this[s[n]]=null}}),r.Interface=u,r.augmentClass=function(e,t){var n=this,r=function(){};r.prototype=n.prototype;var a=new r;o(a,e.prototype),e.prototype=a,e.prototype.constructor=e,e.Interface=o({},n.Interface,t),e.augmentClass=n.augmentClass,i.addPoolingTo(e,i.fourArgumentPooler)},i.addPoolingTo(r,i.fourArgumentPooler),t.exports=r},{130:130,143:143,144:144,24:24}],81:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i={relatedTarget:null};o.augmentClass(r,i),t.exports=r},{87:87}],82:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={data:null};o.augmentClass(r,i),t.exports=r},{80:80}],83:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(99),a=e(100),s=e(101),u={key:a,location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:s,charCode:function(e){return"keypress"===e.type?i(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?i(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}};o.augmentClass(r,u),t.exports=r},{100:100,101:101,87:87,99:99}],84:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(90),a=e(101),s={screenX:null,screenY:null,clientX:null,clientY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:a,button:function(e){var t=e.button;return"which"in e?t:2===t?2:4===t?1:0},buttons:null,relatedTarget:function(e){return e.relatedTarget||(e.fromElement===e.srcElement?e.toElement:e.fromElement)},pageX:function(e){return"pageX"in e?e.pageX:e.clientX+i.currentScrollLeft},pageY:function(e){return"pageY"in e?e.pageY:e.clientY+i.currentScrollTop}};o.augmentClass(r,s),t.exports=r},{101:101,87:87,90:90}],85:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(101),a={touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:i};o.augmentClass(r,a),t.exports=r},{101:101,87:87}],86:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={propertyName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),t.exports=r},{80:80}],87:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i=e(102),a={view:function(e){if(e.view)return e.view;var t=i(e);if(t.window===t)return t;var n=t.ownerDocument;return n?n.defaultView||n.parentWindow:window},detail:function(e){return e.detail||0}};o.augmentClass(r,a),t.exports=r},{102:102,80:80}],88:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(84),i={deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:null,deltaMode:null};o.augmentClass(r,i),t.exports=r},{84:84}],89:[function(e,t,n){"use strict";var r=e(113),o=(e(138),{}),i={reinitializeTransaction:function(){this.transactionWrappers=this.getTransactionWrappers(),this.wrapperInitData?this.wrapperInitData.length=0:this.wrapperInitData=[],this._isInTransaction=!1},_isInTransaction:!1,getTransactionWrappers:null,isInTransaction:function(){return!!this._isInTransaction},perform:function(e,t,n,o,i,a,s,u){this.isInTransaction()&&r("27");var l,c;try{this._isInTransaction=!0,l=!0,this.initializeAll(0),c=e.call(t,n,o,i,a,s,u),l=!1}finally{try{if(l)try{this.closeAll(0)}catch(e){}else this.closeAll(0)}finally{this._isInTransaction=!1}}return c},initializeAll:function(e){for(var t=this.transactionWrappers,n=e;n<t.length;n++){var r=t[n];try{this.wrapperInitData[n]=o,this.wrapperInitData[n]=r.initialize?r.initialize.call(this):null}finally{if(this.wrapperInitData[n]===o)try{this.initializeAll(n+1)}catch(e){}}}},closeAll:function(e){this.isInTransaction()||r("28");for(var t=this.transactionWrappers,n=e;n<t.length;n++){var i,a=t[n],s=this.wrapperInitData[n];try{i=!0,s!==o&&a.close&&a.close.call(this,s),i=!1}finally{if(i)try{this.closeAll(n+1)}catch(e){}}}this.wrapperInitData.length=0}};t.exports=i},{113:113,138:138}],90:[function(e,t,n){"use strict";var r={currentScrollLeft:0,currentScrollTop:0,refreshScrollValues:function(e){r.currentScrollLeft=e.x,r.currentScrollTop=e.y}};t.exports=r},{}],91:[function(e,t,n){"use strict";function r(e,t){return null==t&&o("30"),null==e?t:Array.isArray(e)?Array.isArray(t)?(e.push.apply(e,t),e):(e.push(t),e):Array.isArray(t)?[e].concat(t):[e,t]}var o=e(113);e(138);t.exports=r},{113:113,138:138}],92:[function(e,t,n){"use strict";function r(e){for(var t=1,n=0,r=0,i=e.length,a=-4&i;r<a;){for(var s=Math.min(r+4096,a);r<s;r+=4)n+=(t+=e.charCodeAt(r))+(t+=e.charCodeAt(r+1))+(t+=e.charCodeAt(r+2))+(t+=e.charCodeAt(r+3));t%=o,n%=o}for(;r<i;r++)n+=t+=e.charCodeAt(r);return t%=o,n%=o,t|n<<16}var o=65521;t.exports=r},{}],93:[function(e,t,n){"use strict";var r=function(e){return"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(t,n,r,o){MSApp.execUnsafeLocalFunction(function(){return e(t,n,r,o)})}:e};t.exports=r},{}],94:[function(e,t,n){"use strict";function r(e,t,n,r){if(null==t||"boolean"==typeof t||""===t)return"";var o=isNaN(t);return r||o||0===t||i.hasOwnProperty(e)&&i[e]?""+t:("string"==typeof t&&(t=t.trim()),t+"px")}var o=e(4),i=(e(143),o.isUnitlessNumber);t.exports=r},{143:143,4:4}],95:[function(e,t,n){"use strict";function r(e){var t=""+e,n=i.exec(t);if(!n)return t;var r,o="",a=0,s=0;for(a=n.index;a<t.length;a++){switch(t.charCodeAt(a)){case 34:r="&quot;";break;case 38:r="&amp;";break;case 39:r="&#x27;";break;case 60:r="&lt;";break;case 62:r="&gt;";break;default:continue}s!==a&&(o+=t.substring(s,a)),s=a+1,o+=r}return s!==a?o+t.substring(s,a):o}function o(e){return"boolean"==typeof e||"number"==typeof e?""+e:r(e)}var i=/["'&<>]/;t.exports=o},{}],96:[function(e,t,n){"use strict";function r(e){if(null==e)return null;if(1===e.nodeType)return e;var t=a.get(e);if(t)return t=s(t),t?i.getNodeFromInstance(t):null;"function"==typeof e.render?o("44"):o("45",Object.keys(e))}var o=e(113),i=(e(120),e(33)),a=e(57),s=e(103);e(138),e(143);t.exports=r},{103:103,113:113,120:120,138:138,143:143,33:33,57:57}],97:[function(e,t,n){(function(n){"use strict";function r(e,t,n,r){if(e&&"object"==typeof e){var o=e;void 0===o[n]&&null!=t&&(o[n]=t)}}function o(e,t){if(null==e)return e;var n={};return i(e,r,n),n}var i=(e(22),e(118));e(143);void 0!==n&&n.env,t.exports=o}).call(this,void 0)},{118:118,143:143,22:22}],98:[function(e,t,n){"use strict";function r(e,t,n){Array.isArray(e)?e.forEach(t,n):e&&t.call(n,e)}t.exports=r},{}],99:[function(e,t,n){"use strict";function r(e){var t,n=e.keyCode;return"charCode"in e?0===(t=e.charCode)&&13===n&&(t=13):t=n,t>=32||13===t?t:0}t.exports=r},{}],100:[function(e,t,n){"use strict";function r(e){if(e.key){var t=i[e.key]||e.key;if("Unidentified"!==t)return t}if("keypress"===e.type){var n=o(e);return 13===n?"Enter":String.fromCharCode(n)}return"keydown"===e.type||"keyup"===e.type?a[e.keyCode]||"Unidentified":""}var o=e(99),i={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},a={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"};t.exports=r},{99:99}],101:[function(e,t,n){"use strict";function r(e){var t=this,n=t.nativeEvent;if(n.getModifierState)return n.getModifierState(e);var r=i[e];return!!r&&!!n[r]}function o(e){return r}var i={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};t.exports=o},{}],102:[function(e,t,n){"use strict";function r(e){var t=e.target||e.srcElement||window;return t.correspondingUseElement&&(t=t.correspondingUseElement),3===t.nodeType?t.parentNode:t}t.exports=r},{}],103:[function(e,t,n){"use strict";function r(e){for(var t;(t=e._renderedNodeType)===o.COMPOSITE;)e=e._renderedComponent;return t===o.HOST?e._renderedComponent:t===o.EMPTY?null:void 0}var o=e(62);t.exports=r},{62:62}],104:[function(e,t,n){"use strict";function r(e){var t=e&&(o&&e[o]||e[i]);if("function"==typeof t)return t}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";t.exports=r},{}],105:[function(e,t,n){"use strict";function r(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function o(e){for(;e;){if(e.nextSibling)return e.nextSibling;e=e.parentNode}}function i(e,t){for(var n=r(e),i=0,a=0;n;){if(3===n.nodeType){if(a=i+n.textContent.length,i<=t&&a>=t)return{node:n,offset:t-i};i=a}n=r(o(n))}}t.exports=i},{}],106:[function(e,t,n){"use strict";function r(){return!i&&o.canUseDOM&&(i="textContent"in document.documentElement?"textContent":"innerText"),i}var o=e(124),i=null;t.exports=r},{124:124}],107:[function(e,t,n){"use strict";function r(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n["ms"+e]="MS"+t,n["O"+e]="o"+t.toLowerCase(),n}function o(e){if(s[e])return s[e];if(!a[e])return e;var t=a[e];for(var n in t)if(t.hasOwnProperty(n)&&n in u)return s[e]=t[n];return""}var i=e(124),a={animationend:r("Animation","AnimationEnd"),animationiteration:r("Animation","AnimationIteration"),animationstart:r("Animation","AnimationStart"),transitionend:r("Transition","TransitionEnd")},s={},u={};i.canUseDOM&&(u=document.createElement("div").style,"AnimationEvent"in window||(delete a.animationend.animation,delete a.animationiteration.animation,delete a.animationstart.animation),"TransitionEvent"in window||delete a.transitionend.transition),t.exports=o},{124:124}],108:[function(e,t,n){"use strict";function r(e){var t=e.type,n=e.nodeName;return n&&"input"===n.toLowerCase()&&("checkbox"===t||"radio"===t)}function o(e){return e._wrapperState.valueTracker}function i(e,t){e._wrapperState.valueTracker=t}function a(e){delete e._wrapperState.valueTracker}function s(e){var t;return e&&(t=r(e)?""+e.checked:e.value),t}var u=e(33),l={_getTrackerFromNode:function(e){return o(u.getInstanceFromNode(e))},track:function(e){if(!o(e)){var t=u.getNodeFromInstance(e),n=r(t)?"checked":"value",s=Object.getOwnPropertyDescriptor(t.constructor.prototype,n),l=""+t[n];t.hasOwnProperty(n)||"function"!=typeof s.get||"function"!=typeof s.set||(Object.defineProperty(t,n,{enumerable:s.enumerable,configurable:!0,get:function(){return s.get.call(this)},set:function(e){l=""+e,s.set.call(this,e)}}),i(e,{getValue:function(){return l},setValue:function(e){l=""+e},stopTracking:function(){a(e),delete t[n]}}))}},updateValueIfChanged:function(e){if(!e)return!1;var t=o(e);if(!t)return l.track(e),!0;var n=t.getValue(),r=s(u.getNodeFromInstance(e));return r!==n&&(t.setValue(r),!0)},stopTracking:function(e){var t=o(e);t&&t.stopTracking()}};t.exports=l},{33:33}],109:[function(e,t,n){"use strict";function r(e){if(e){var t=e.getName();if(t)return" Check the render method of `"+t+"`."}return""}function o(e){return"function"==typeof e&&void 0!==e.prototype&&"function"==typeof e.prototype.mountComponent&&"function"==typeof e.prototype.receiveComponent}function i(e,t){var n;if(null===e||!1===e)n=l.create(i);else if("object"==typeof e){var s=e,u=s.type;if("function"!=typeof u&&"string"!=typeof u){var d="";d+=r(s._owner),a("130",null==u?u:typeof u,d)}"string"==typeof s.type?n=c.createInternalComponent(s):o(s.type)?(n=new s.type(s),n.getHostNode||(n.getHostNode=n.getNativeNode)):n=new p(s)}else"string"==typeof e||"number"==typeof e?n=c.createInstanceForText(e):a("131",typeof e);return n._mountIndex=0,n._mountImage=null,n}var a=e(113),s=e(144),u=e(29),l=e(49),c=e(54),p=(e(122),e(138),e(143),function(e){this.construct(e)});s(p.prototype,u,{_instantiateReactComponent:i}),t.exports=i},{113:113,122:122,138:138,143:143,144:144,29:29,49:49,54:54}],110:[function(e,t,n){"use strict";function r(e,t){if(!i.canUseDOM||t&&!("addEventListener"in document))return!1;var n="on"+e,r=n in document;if(!r){var a=document.createElement("div");a.setAttribute(n,"return;"),r="function"==typeof a[n]}return!r&&o&&"wheel"===e&&(r=document.implementation.hasFeature("Events.wheel","3.0")),r}var o,i=e(124);i.canUseDOM&&(o=document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature("","")),t.exports=r},{124:124}],111:[function(e,t,n){"use strict";function r(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!o[e.type]:"textarea"===t}var o={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};t.exports=r},{}],112:[function(e,t,n){"use strict";function r(e){return'"'+o(e)+'"'}var o=e(95);t.exports=r},{95:95}],113:[function(e,t,n){"use strict";function r(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r<t;r++)n+="&args[]="+encodeURIComponent(arguments[r+1]);n+=" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";var o=new Error(n);throw o.name="Invariant Violation",o.framesToPop=1,o}t.exports=r},{}],114:[function(e,t,n){"use strict";var r=e(60);t.exports=r.renderSubtreeIntoContainer},{60:60}],115:[function(e,t,n){"use strict";var r,o=e(124),i=e(10),a=/^[ \r\n\t\f]/,s=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,u=e(93),l=u(function(e,t){if(e.namespaceURI!==i.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML="<svg>"+t+"</svg>";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(o.canUseDOM){var c=document.createElement("div");c.innerHTML=" ",""===c.innerHTML&&(l=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&s.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),c=null}t.exports=l},{10:10,124:124,93:93}],116:[function(e,t,n){"use strict";var r=e(124),o=e(95),i=e(115),a=function(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t};r.canUseDOM&&("textContent"in document.documentElement||(a=function(e,t){if(3===e.nodeType)return void(e.nodeValue=t);i(e,o(t))})),t.exports=a},{115:115,124:124,95:95}],117:[function(e,t,n){"use strict";function r(e,t){var n=null===e||!1===e,r=null===t||!1===t;if(n||r)return n===r;var o=typeof e,i=typeof t;return"string"===o||"number"===o?"string"===i||"number"===i:"object"===i&&e.type===t.type&&e.key===t.key}t.exports=r},{}],118:[function(e,t,n){"use strict";function r(e,t){return e&&"object"==typeof e&&null!=e.key?l.escape(e.key):t.toString(36)}function o(e,t,n,i){var d=typeof e;if("undefined"!==d&&"boolean"!==d||(e=null),null===e||"string"===d||"number"===d||"object"===d&&e.$$typeof===s)return n(i,e,""===t?c+r(e,0):t),1;var f,h,m=0,v=""===t?c:t+p;if(Array.isArray(e))for(var g=0;g<e.length;g++)f=e[g],h=v+r(f,g),m+=o(f,h,n,i);else{var y=u(e);if(y){var _,C=y.call(e);if(y!==e.entries)for(var b=0;!(_=C.next()).done;)f=_.value,h=v+r(f,b++),m+=o(f,h,n,i);else for(;!(_=C.next()).done;){var E=_.value;E&&(f=E[1],h=v+l.escape(E[0])+p+r(f,0),m+=o(f,h,n,i))}}else if("object"===d){var x=String(e);a("31","[object Object]"===x?"object with keys {"+Object.keys(e).join(", ")+"}":x,"")}}return m}function i(e,t,n){return null==e?0:o(e,"",t,n)}var a=e(113),s=(e(120),e(48)),u=e(104),l=(e(138),e(22)),c=(e(143),"."),p=":";t.exports=i},{104:104,113:113,120:120,138:138,143:143,22:22,48:48}],119:[function(e,t,n){"use strict";var r=(e(144),e(130)),o=(e(143),r);t.exports=o},{130:130,143:143,144:144}],120:[function(t,n,r){"use strict";var o=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;n.exports=o.ReactCurrentOwner},{}],121:[function(t,n,r){"use strict";n.exports=e},{}],122:[function(t,n,r){"use strict";var o=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;n.exports=o.getNextDebugID},{}],123:[function(e,t,n){"use strict";var r=e(130),o={listen:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!1),{remove:function(){e.removeEventListener(t,n,!1)}}):e.attachEvent?(e.attachEvent("on"+t,n),{remove:function(){e.detachEvent("on"+t,n)}}):void 0},capture:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!0),{remove:function(){e.removeEventListener(t,n,!0)}}):{remove:r}},registerDefault:function(){}};t.exports=o},{130:130}],124:[function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};t.exports=o},{}],125:[function(e,t,n){"use strict";function r(e){return e.replace(o,function(e,t){return t.toUpperCase()})}var o=/-(.)/g;t.exports=r},{}],126:[function(e,t,n){"use strict";function r(e){return o(e.replace(i,"ms-"))}var o=e(125),i=/^-ms-/;t.exports=r},{125:125}],127:[function(e,t,n){"use strict";function r(e,t){return!(!e||!t)&&(e===t||!o(e)&&(o(t)?r(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}var o=e(140);t.exports=r},{140:140}],128:[function(e,t,n){"use strict";function r(e){var t=e.length;if((Array.isArray(e)||"object"!=typeof e&&"function"!=typeof e)&&a(!1),"number"!=typeof t&&a(!1),0===t||t-1 in e||a(!1),"function"==typeof e.callee&&a(!1),e.hasOwnProperty)try{return Array.prototype.slice.call(e)}catch(e){}for(var n=Array(t),r=0;r<t;r++)n[r]=e[r];return n}function o(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"length"in e&&!("setInterval"in e)&&"number"!=typeof e.nodeType&&(Array.isArray(e)||"callee"in e||"item"in e)}function i(e){return o(e)?Array.isArray(e)?e.slice():r(e):[e]}var a=e(138);t.exports=i},{138:138}],129:[function(e,t,n){"use strict";function r(e){var t=e.match(c);return t&&t[1].toLowerCase()}function o(e,t){var n=l;l||u(!1);var o=r(e),i=o&&s(o);if(i){n.innerHTML=i[1]+e+i[2];for(var c=i[0];c--;)n=n.lastChild}else n.innerHTML=e;var p=n.getElementsByTagName("script");p.length&&(t||u(!1),a(p).forEach(t));for(var d=Array.from(n.childNodes);n.lastChild;)n.removeChild(n.lastChild);return d}var i=e(124),a=e(128),s=e(134),u=e(138),l=i.canUseDOM?document.createElement("div"):null,c=/^\s*<(\w+)/;t.exports=o},{124:124,128:128,134:134,138:138}],130:[function(e,t,n){"use strict";function r(e){return function(){return e}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},t.exports=o},{}],131:[function(e,t,n){"use strict";var r={};t.exports=r},{}],132:[function(e,t,n){"use strict";function r(e){try{e.focus()}catch(e){}}t.exports=r},{}],133:[function(e,t,n){"use strict";function r(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}t.exports=r},{}],134:[function(e,t,n){"use strict";function r(e){return a||i(!1),d.hasOwnProperty(e)||(e="*"),s.hasOwnProperty(e)||(a.innerHTML="*"===e?"<link />":"<"+e+"></"+e+">",s[e]=!a.firstChild),s[e]?d[e]:null}var o=e(124),i=e(138),a=o.canUseDOM?document.createElement("div"):null,s={},u=[1,'<select multiple="true">',"</select>"],l=[1,"<table>","</table>"],c=[3,"<table><tbody><tr>","</tr></tbody></table>"],p=[1,'<svg xmlns="http://www.w3.org/2000/svg">',"</svg>"],d={"*":[1,"?<div>","</div>"],area:[1,"<map>","</map>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],legend:[1,"<fieldset>","</fieldset>"],param:[1,"<object>","</object>"],tr:[2,"<table><tbody>","</tbody></table>"],optgroup:u,option:u,caption:l,colgroup:l,tbody:l,tfoot:l,thead:l,td:c,th:c};["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"].forEach(function(e){d[e]=p,s[e]=!0}),t.exports=r},{124:124,138:138}],135:[function(e,t,n){"use strict";function r(e){return e.Window&&e instanceof e.Window?{x:e.pageXOffset||e.document.documentElement.scrollLeft,y:e.pageYOffset||e.document.documentElement.scrollTop}:{x:e.scrollLeft,y:e.scrollTop}}t.exports=r},{}],136:[function(e,t,n){"use strict";function r(e){return e.replace(o,"-$1").toLowerCase()}var o=/([A-Z])/g;t.exports=r},{}],137:[function(e,t,n){"use strict";function r(e){return o(e).replace(i,"-ms-")}var o=e(136),i=/^ms-/;t.exports=r},{136:136}],138:[function(e,t,n){"use strict";function r(e,t,n,r,i,a,s,u){if(o(t),!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,i,a,s,u],p=0;l=new Error(t.replace(/%s/g,function(){return c[p++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}}var o=function(e){};t.exports=r},{}],139:[function(e,t,n){"use strict";function r(e){var t=e?e.ownerDocument||e:document,n=t.defaultView||window;return!(!e||!("function"==typeof n.Node?e instanceof n.Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName))}t.exports=r},{}],140:[function(e,t,n){"use strict";function r(e){return o(e)&&3==e.nodeType}var o=e(139);t.exports=r},{139:139}],141:[function(e,t,n){"use strict";function r(e){var t={};return function(n){return t.hasOwnProperty(n)||(t[n]=e.call(this,n)),t[n]}}t.exports=r},{}],142:[function(e,t,n){"use strict";function r(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!==e&&t!==t}function o(e,t){if(r(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(var a=0;a<n.length;a++)if(!i.call(t,n[a])||!r(e[n[a]],t[n[a]]))return!1;return!0}var i=Object.prototype.hasOwnProperty;t.exports=o},{}],143:[function(e,t,n){"use strict";var r=e(130),o=r;t.exports=o},{130:130}],144:[function(e,t,n){"use strict";function r(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}var o=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;t.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=r(e),l=1;l<arguments.length;l++){n=Object(arguments[l]);for(var c in n)i.call(n,c)&&(u[c]=n[c]);if(o){s=o(n);for(var p=0;p<s.length;p++)a.call(n,s[p])&&(u[s[p]]=n[s[p]])}}return u}},{}],145:[function(e,t,n){"use strict";function r(e,t,n,r,o){}t.exports=r},{138:138,143:143,148:148}],146:[function(e,t,n){"use strict";var r=e(147);t.exports=function(e){return r(e,!1)}},{147:147}],147:[function(e,t,n){"use strict";var r=e(130),o=e(138),i=e(143),a=e(148),s=e(145);t.exports=function(e,t){function n(e){var t=e&&(w&&e[w]||e[T]);if("function"==typeof t)return t}function u(e,t){return e===t?0!==e||1/e==1/t:e!==e&&t!==t}function l(e){this.message=e,this.stack=""}function c(e){function n(n,r,i,s,u,c,p){if(s=s||k,c=c||i,p!==a)if(t)o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types");else;return null==r[i]?n?new l(null===r[i]?"The "+u+" `"+c+"` is marked as required in `"+s+"`, but its value is `null`.":"The "+u+" `"+c+"` is marked as required in `"+s+"`, but its value is `undefined`."):null:e(r,i,s,u,c)}var r=n.bind(null,!1);return r.isRequired=n.bind(null,!0),r}function p(e){function t(t,n,r,o,i,a){var s=t[n];if(C(s)!==e)return new l("Invalid "+o+" `"+i+"` of type `"+b(s)+"` supplied to `"+r+"`, expected `"+e+"`.");return null}return c(t)}function d(e){function t(t,n,r,o,i){if("function"!=typeof e)return new l("Property `"+i+"` of component `"+r+"` has invalid PropType notation inside arrayOf.");var s=t[n];if(!Array.isArray(s)){return new l("Invalid "+o+" `"+i+"` of type `"+C(s)+"` supplied to `"+r+"`, expected an array.")}for(var u=0;u<s.length;u++){var c=e(s,u,r,o,i+"["+u+"]",a);if(c instanceof Error)return c}return null}return c(t)}function f(e){function t(t,n,r,o,i){if(!(t[n]instanceof e)){var a=e.name||k;return new l("Invalid "+o+" `"+i+"` of type `"+x(t[n])+"` supplied to `"+r+"`, expected instance of `"+a+"`.")}return null}return c(t)}function h(e){function t(t,n,r,o,i){for(var a=t[n],s=0;s<e.length;s++)if(u(a,e[s]))return null;return new l("Invalid "+o+" `"+i+"` of value `"+a+"` supplied to `"+r+"`, expected one of "+JSON.stringify(e)+".")}return Array.isArray(e)?c(t):r.thatReturnsNull}function m(e){function t(t,n,r,o,i){if("function"!=typeof e)return new l("Property `"+i+"` of component `"+r+"` has invalid PropType notation inside objectOf.");var s=t[n],u=C(s);if("object"!==u)return new l("Invalid "+o+" `"+i+"` of type `"+u+"` supplied to `"+r+"`, expected an object.");for(var c in s)if(s.hasOwnProperty(c)){var p=e(s,c,r,o,i+"."+c,a);if(p instanceof Error)return p}return null}return c(t)}function v(e){function t(t,n,r,o,i){for(var s=0;s<e.length;s++){if(null==(0,e[s])(t,n,r,o,i,a))return null}return new l("Invalid "+o+" `"+i+"` supplied to `"+r+"`.")}if(!Array.isArray(e))return r.thatReturnsNull;for(var n=0;n<e.length;n++){var o=e[n];if("function"!=typeof o)return i(!1,"Invalid argument supplid to oneOfType. Expected an array of check functions, but received %s at index %s.",E(o),n),r.thatReturnsNull}return c(t)}function g(e){function t(t,n,r,o,i){var s=t[n],u=C(s);if("object"!==u)return new l("Invalid "+o+" `"+i+"` of type `"+u+"` supplied to `"+r+"`, expected `object`.");for(var c in e){
var p=e[c];if(p){var d=p(s,c,r,o,i+"."+c,a);if(d)return d}}return null}return c(t)}function y(t){switch(typeof t){case"number":case"string":case"undefined":return!0;case"boolean":return!t;case"object":if(Array.isArray(t))return t.every(y);if(null===t||e(t))return!0;var r=n(t);if(!r)return!1;var o,i=r.call(t);if(r!==t.entries){for(;!(o=i.next()).done;)if(!y(o.value))return!1}else for(;!(o=i.next()).done;){var a=o.value;if(a&&!y(a[1]))return!1}return!0;default:return!1}}function _(e,t){return"symbol"===e||("Symbol"===t["@@toStringTag"]||"function"==typeof Symbol&&t instanceof Symbol)}function C(e){var t=typeof e;return Array.isArray(e)?"array":e instanceof RegExp?"object":_(t,e)?"symbol":t}function b(e){if(void 0===e||null===e)return""+e;var t=C(e);if("object"===t){if(e instanceof Date)return"date";if(e instanceof RegExp)return"regexp"}return t}function E(e){var t=b(e);switch(t){case"array":case"object":return"an "+t;case"boolean":case"date":case"regexp":return"a "+t;default:return t}}function x(e){return e.constructor&&e.constructor.name?e.constructor.name:k}var w="function"==typeof Symbol&&Symbol.iterator,T="@@iterator",k="<<anonymous>>",P={array:p("array"),bool:p("boolean"),func:p("function"),number:p("number"),object:p("object"),string:p("string"),symbol:p("symbol"),any:function(){return c(r.thatReturnsNull)}(),arrayOf:d,element:function(){function t(t,n,r,o,i){var a=t[n];if(!e(a)){return new l("Invalid "+o+" `"+i+"` of type `"+C(a)+"` supplied to `"+r+"`, expected a single ReactElement.")}return null}return c(t)}(),instanceOf:f,node:function(){function e(e,t,n,r,o){return y(e[t])?null:new l("Invalid "+r+" `"+o+"` supplied to `"+n+"`, expected a ReactNode.")}return c(e)}(),objectOf:m,oneOf:h,oneOfType:v,shape:g};return l.prototype=Error.prototype,P.checkPropTypes=s,P.PropTypes=P,P}},{130:130,138:138,143:143,145:145,148:148}],148:[function(e,t,n){"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}]},{},[45])(45)}()}()});

    __LiteMolReactDOM = __module__.exports;
})();


var __LiteMolColorPicker = {};

/*

The MIT License (MIT)

Copyright (c) 2015 Case Sandberg

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(modules) { // webpackBootstrap
/******/  var __self = {};				
/******/ 	var parentHotUpdateCallback = __self["webpackHotUpdate"];
/******/ 	__self["webpackHotUpdate"] = 
/******/ 	function webpackHotUpdateCallback(chunkId, moreModules) { // eslint-disable-line no-unused-vars
/******/ 		hotAddUpdateChunk(chunkId, moreModules);
/******/ 		if(parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
/******/ 	}
/******/ 	
/******/ 	function hotDownloadUpdateChunk(chunkId) { // eslint-disable-line no-unused-vars
/******/ 		var head = document.getElementsByTagName("head")[0];
/******/ 		var script = document.createElement("script");
/******/ 		script.type = "text/javascript";
/******/ 		script.charset = "utf-8";
/******/ 		script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js";
/******/ 		head.appendChild(script);
/******/ 	}
/******/ 	
/******/ 	function hotDownloadManifest(callback) { // eslint-disable-line no-unused-vars
/******/ 		if(typeof XMLHttpRequest === "undefined")
/******/ 			return callback(new Error("No browser support"));
/******/ 		try {
/******/ 			var request = new XMLHttpRequest();
/******/ 			var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json";
/******/ 			request.open("GET", requestPath, true);
/******/ 			request.timeout = 10000;
/******/ 			request.send(null);
/******/ 		} catch(err) {
/******/ 			return callback(err);
/******/ 		}
/******/ 		request.onreadystatechange = function() {
/******/ 			if(request.readyState !== 4) return;
/******/ 			if(request.status === 0) {
/******/ 				// timeout
/******/ 				callback(new Error("Manifest request to " + requestPath + " timed out."));
/******/ 			} else if(request.status === 404) {
/******/ 				// no update available
/******/ 				callback();
/******/ 			} else if(request.status !== 200 && request.status !== 304) {
/******/ 				// other failure
/******/ 				callback(new Error("Manifest request to " + requestPath + " failed."));
/******/ 			} else {
/******/ 				// success
/******/ 				try {
/******/ 					var update = JSON.parse(request.responseText);
/******/ 				} catch(e) {
/******/ 					callback(e);
/******/ 					return;
/******/ 				}
/******/ 				callback(null, update);
/******/ 			}
/******/ 		};
/******/ 	}

/******/ 	
/******/ 	
/******/ 	// Copied from https://github.com/facebook/react/blob/bef45b0/src/shared/utils/canDefineProperty.js
/******/ 	var canDefineProperty = false;
/******/ 	try {
/******/ 		Object.defineProperty({}, "x", {
/******/ 			get: function() {}
/******/ 		});
/******/ 		canDefineProperty = true;
/******/ 	} catch(x) {
/******/ 		// IE will fail on defineProperty
/******/ 	}
/******/ 	
/******/ 	var hotApplyOnUpdate = true;
/******/ 	var hotCurrentHash = "cac23860c44b0ba80f83"; // eslint-disable-line no-unused-vars
/******/ 	var hotCurrentModuleData = {};
/******/ 	var hotCurrentParents = []; // eslint-disable-line no-unused-vars
/******/ 	
/******/ 	function hotCreateRequire(moduleId) { // eslint-disable-line no-unused-vars
/******/ 		var me = installedModules[moduleId];
/******/ 		if(!me) return __webpack_require__;
/******/ 		var fn = function(request) {
/******/ 			if(me.hot.active) {
/******/ 				if(installedModules[request]) {
/******/ 					if(installedModules[request].parents.indexOf(moduleId) < 0)
/******/ 						installedModules[request].parents.push(moduleId);
/******/ 					if(me.children.indexOf(request) < 0)
/******/ 						me.children.push(request);
/******/ 				} else hotCurrentParents = [moduleId];
/******/ 			} else {
/******/ 				console.warn("[HMR] unexpected require(" + request + ") from disposed module " + moduleId);
/******/ 				hotCurrentParents = [];
/******/ 			}
/******/ 			return __webpack_require__(request);
/******/ 		};
/******/ 		for(var name in __webpack_require__) {
/******/ 			if(Object.prototype.hasOwnProperty.call(__webpack_require__, name)) {
/******/ 				if(canDefineProperty) {
/******/ 					Object.defineProperty(fn, name, (function(name) {
/******/ 						return {
/******/ 							configurable: true,
/******/ 							enumerable: true,
/******/ 							get: function() {
/******/ 								return __webpack_require__[name];
/******/ 							},
/******/ 							set: function(value) {
/******/ 								__webpack_require__[name] = value;
/******/ 							}
/******/ 						};
/******/ 					}(name)));
/******/ 				} else {
/******/ 					fn[name] = __webpack_require__[name];
/******/ 				}
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		function ensure(chunkId, callback) {
/******/ 			if(hotStatus === "ready")
/******/ 				hotSetStatus("prepare");
/******/ 			hotChunksLoading++;
/******/ 			__webpack_require__.e(chunkId, function() {
/******/ 				try {
/******/ 					callback.call(null, fn);
/******/ 				} finally {
/******/ 					finishChunkLoading();
/******/ 				}
/******/ 	
/******/ 				function finishChunkLoading() {
/******/ 					hotChunksLoading--;
/******/ 					if(hotStatus === "prepare") {
/******/ 						if(!hotWaitingFilesMap[chunkId]) {
/******/ 							hotEnsureUpdateChunk(chunkId);
/******/ 						}
/******/ 						if(hotChunksLoading === 0 && hotWaitingFiles === 0) {
/******/ 							hotUpdateDownloaded();
/******/ 						}
/******/ 					}
/******/ 				}
/******/ 			});
/******/ 		}
/******/ 		if(canDefineProperty) {
/******/ 			Object.defineProperty(fn, "e", {
/******/ 				enumerable: true,
/******/ 				value: ensure
/******/ 			});
/******/ 		} else {
/******/ 			fn.e = ensure;
/******/ 		}
/******/ 		return fn;
/******/ 	}
/******/ 	
/******/ 	function hotCreateModule(moduleId) { // eslint-disable-line no-unused-vars
/******/ 		var hot = {
/******/ 			// private stuff
/******/ 			_acceptedDependencies: {},
/******/ 			_declinedDependencies: {},
/******/ 			_selfAccepted: false,
/******/ 			_selfDeclined: false,
/******/ 			_disposeHandlers: [],
/******/ 	
/******/ 			// Module API
/******/ 			active: true,
/******/ 			accept: function(dep, callback) {
/******/ 				if(typeof dep === "undefined")
/******/ 					hot._selfAccepted = true;
/******/ 				else if(typeof dep === "function")
/******/ 					hot._selfAccepted = dep;
/******/ 				else if(typeof dep === "object")
/******/ 					for(var i = 0; i < dep.length; i++)
/******/ 						hot._acceptedDependencies[dep[i]] = callback;
/******/ 				else
/******/ 					hot._acceptedDependencies[dep] = callback;
/******/ 			},
/******/ 			decline: function(dep) {
/******/ 				if(typeof dep === "undefined")
/******/ 					hot._selfDeclined = true;
/******/ 				else if(typeof dep === "number")
/******/ 					hot._declinedDependencies[dep] = true;
/******/ 				else
/******/ 					for(var i = 0; i < dep.length; i++)
/******/ 						hot._declinedDependencies[dep[i]] = true;
/******/ 			},
/******/ 			dispose: function(callback) {
/******/ 				hot._disposeHandlers.push(callback);
/******/ 			},
/******/ 			addDisposeHandler: function(callback) {
/******/ 				hot._disposeHandlers.push(callback);
/******/ 			},
/******/ 			removeDisposeHandler: function(callback) {
/******/ 				var idx = hot._disposeHandlers.indexOf(callback);
/******/ 				if(idx >= 0) hot._disposeHandlers.splice(idx, 1);
/******/ 			},
/******/ 	
/******/ 			// Management API
/******/ 			check: hotCheck,
/******/ 			apply: hotApply,
/******/ 			status: function(l) {
/******/ 				if(!l) return hotStatus;
/******/ 				hotStatusHandlers.push(l);
/******/ 			},
/******/ 			addStatusHandler: function(l) {
/******/ 				hotStatusHandlers.push(l);
/******/ 			},
/******/ 			removeStatusHandler: function(l) {
/******/ 				var idx = hotStatusHandlers.indexOf(l);
/******/ 				if(idx >= 0) hotStatusHandlers.splice(idx, 1);
/******/ 			},
/******/ 	
/******/ 			//inherit from previous dispose call
/******/ 			data: hotCurrentModuleData[moduleId]
/******/ 		};
/******/ 		return hot;
/******/ 	}
/******/ 	
/******/ 	var hotStatusHandlers = [];
/******/ 	var hotStatus = "idle";
/******/ 	
/******/ 	function hotSetStatus(newStatus) {
/******/ 		hotStatus = newStatus;
/******/ 		for(var i = 0; i < hotStatusHandlers.length; i++)
/******/ 			hotStatusHandlers[i].call(null, newStatus);
/******/ 	}
/******/ 	
/******/ 	// while downloading
/******/ 	var hotWaitingFiles = 0;
/******/ 	var hotChunksLoading = 0;
/******/ 	var hotWaitingFilesMap = {};
/******/ 	var hotRequestedFilesMap = {};
/******/ 	var hotAvailibleFilesMap = {};
/******/ 	var hotCallback;
/******/ 	
/******/ 	// The update info
/******/ 	var hotUpdate, hotUpdateNewHash;
/******/ 	
/******/ 	function toModuleId(id) {
/******/ 		var isNumber = (+id) + "" === id;
/******/ 		return isNumber ? +id : id;
/******/ 	}
/******/ 	
/******/ 	function hotCheck(apply, callback) {
/******/ 		if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status");
/******/ 		if(typeof apply === "function") {
/******/ 			hotApplyOnUpdate = false;
/******/ 			callback = apply;
/******/ 		} else {
/******/ 			hotApplyOnUpdate = apply;
/******/ 			callback = callback || function(err) {
/******/ 				if(err) throw err;
/******/ 			};
/******/ 		}
/******/ 		hotSetStatus("check");
/******/ 		hotDownloadManifest(function(err, update) {
/******/ 			if(err) return callback(err);
/******/ 			if(!update) {
/******/ 				hotSetStatus("idle");
/******/ 				callback(null, null);
/******/ 				return;
/******/ 			}
/******/ 	
/******/ 			hotRequestedFilesMap = {};
/******/ 			hotAvailibleFilesMap = {};
/******/ 			hotWaitingFilesMap = {};
/******/ 			for(var i = 0; i < update.c.length; i++)
/******/ 				hotAvailibleFilesMap[update.c[i]] = true;
/******/ 			hotUpdateNewHash = update.h;
/******/ 	
/******/ 			hotSetStatus("prepare");
/******/ 			hotCallback = callback;
/******/ 			hotUpdate = {};
/******/ 			var chunkId = 0;
/******/ 			{ // eslint-disable-line no-lone-blocks
/******/ 				/*globals chunkId */
/******/ 				hotEnsureUpdateChunk(chunkId);
/******/ 			}
/******/ 			if(hotStatus === "prepare" && hotChunksLoading === 0 && hotWaitingFiles === 0) {
/******/ 				hotUpdateDownloaded();
/******/ 			}
/******/ 		});
/******/ 	}
/******/ 	
/******/ 	function hotAddUpdateChunk(chunkId, moreModules) { // eslint-disable-line no-unused-vars
/******/ 		if(!hotAvailibleFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
/******/ 			return;
/******/ 		hotRequestedFilesMap[chunkId] = false;
/******/ 		for(var moduleId in moreModules) {
/******/ 			if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ 				hotUpdate[moduleId] = moreModules[moduleId];
/******/ 			}
/******/ 		}
/******/ 		if(--hotWaitingFiles === 0 && hotChunksLoading === 0) {
/******/ 			hotUpdateDownloaded();
/******/ 		}
/******/ 	}
/******/ 	
/******/ 	function hotEnsureUpdateChunk(chunkId) {
/******/ 		if(!hotAvailibleFilesMap[chunkId]) {
/******/ 			hotWaitingFilesMap[chunkId] = true;
/******/ 		} else {
/******/ 			hotRequestedFilesMap[chunkId] = true;
/******/ 			hotWaitingFiles++;
/******/ 			hotDownloadUpdateChunk(chunkId);
/******/ 		}
/******/ 	}
/******/ 	
/******/ 	function hotUpdateDownloaded() {
/******/ 		hotSetStatus("ready");
/******/ 		var callback = hotCallback;
/******/ 		hotCallback = null;
/******/ 		if(!callback) return;
/******/ 		if(hotApplyOnUpdate) {
/******/ 			hotApply(hotApplyOnUpdate, callback);
/******/ 		} else {
/******/ 			var outdatedModules = [];
/******/ 			for(var id in hotUpdate) {
/******/ 				if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
/******/ 					outdatedModules.push(toModuleId(id));
/******/ 				}
/******/ 			}
/******/ 			callback(null, outdatedModules);
/******/ 		}
/******/ 	}
/******/ 	
/******/ 	function hotApply(options, callback) {
/******/ 		if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status");
/******/ 		if(typeof options === "function") {
/******/ 			callback = options;
/******/ 			options = {};
/******/ 		} else if(options && typeof options === "object") {
/******/ 			callback = callback || function(err) {
/******/ 				if(err) throw err;
/******/ 			};
/******/ 		} else {
/******/ 			options = {};
/******/ 			callback = callback || function(err) {
/******/ 				if(err) throw err;
/******/ 			};
/******/ 		}
/******/ 	
/******/ 		function getAffectedStuff(module) {
/******/ 			var outdatedModules = [module];
/******/ 			var outdatedDependencies = {};
/******/ 	
/******/ 			var queue = outdatedModules.slice();
/******/ 			while(queue.length > 0) {
/******/ 				var moduleId = queue.pop();
/******/ 				var module = installedModules[moduleId];
/******/ 				if(!module || module.hot._selfAccepted)
/******/ 					continue;
/******/ 				if(module.hot._selfDeclined) {
/******/ 					return new Error("Aborted because of self decline: " + moduleId);
/******/ 				}
/******/ 				if(moduleId === 0) {
/******/ 					return;
/******/ 				}
/******/ 				for(var i = 0; i < module.parents.length; i++) {
/******/ 					var parentId = module.parents[i];
/******/ 					var parent = installedModules[parentId];
/******/ 					if(parent.hot._declinedDependencies[moduleId]) {
/******/ 						return new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId);
/******/ 					}
/******/ 					if(outdatedModules.indexOf(parentId) >= 0) continue;
/******/ 					if(parent.hot._acceptedDependencies[moduleId]) {
/******/ 						if(!outdatedDependencies[parentId])
/******/ 							outdatedDependencies[parentId] = [];
/******/ 						addAllToSet(outdatedDependencies[parentId], [moduleId]);
/******/ 						continue;
/******/ 					}
/******/ 					delete outdatedDependencies[parentId];
/******/ 					outdatedModules.push(parentId);
/******/ 					queue.push(parentId);
/******/ 				}
/******/ 			}
/******/ 	
/******/ 			return [outdatedModules, outdatedDependencies];
/******/ 		}
/******/ 	
/******/ 		function addAllToSet(a, b) {
/******/ 			for(var i = 0; i < b.length; i++) {
/******/ 				var item = b[i];
/******/ 				if(a.indexOf(item) < 0)
/******/ 					a.push(item);
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// at begin all updates modules are outdated
/******/ 		// the "outdated" status can propagate to parents if they don't accept the children
/******/ 		var outdatedDependencies = {};
/******/ 		var outdatedModules = [];
/******/ 		var appliedUpdate = {};
/******/ 		for(var id in hotUpdate) {
/******/ 			if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
/******/ 				var moduleId = toModuleId(id);
/******/ 				var result = getAffectedStuff(moduleId);
/******/ 				if(!result) {
/******/ 					if(options.ignoreUnaccepted)
/******/ 						continue;
/******/ 					hotSetStatus("abort");
/******/ 					return callback(new Error("Aborted because " + moduleId + " is not accepted"));
/******/ 				}
/******/ 				if(result instanceof Error) {
/******/ 					hotSetStatus("abort");
/******/ 					return callback(result);
/******/ 				}
/******/ 				appliedUpdate[moduleId] = hotUpdate[moduleId];
/******/ 				addAllToSet(outdatedModules, result[0]);
/******/ 				for(var moduleId in result[1]) {
/******/ 					if(Object.prototype.hasOwnProperty.call(result[1], moduleId)) {
/******/ 						if(!outdatedDependencies[moduleId])
/******/ 							outdatedDependencies[moduleId] = [];
/******/ 						addAllToSet(outdatedDependencies[moduleId], result[1][moduleId]);
/******/ 					}
/******/ 				}
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// Store self accepted outdated modules to require them later by the module system
/******/ 		var outdatedSelfAcceptedModules = [];
/******/ 		for(var i = 0; i < outdatedModules.length; i++) {
/******/ 			var moduleId = outdatedModules[i];
/******/ 			if(installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted)
/******/ 				outdatedSelfAcceptedModules.push({
/******/ 					module: moduleId,
/******/ 					errorHandler: installedModules[moduleId].hot._selfAccepted
/******/ 				});
/******/ 		}
/******/ 	
/******/ 		// Now in "dispose" phase
/******/ 		hotSetStatus("dispose");
/******/ 		var queue = outdatedModules.slice();
/******/ 		while(queue.length > 0) {
/******/ 			var moduleId = queue.pop();
/******/ 			var module = installedModules[moduleId];
/******/ 			if(!module) continue;
/******/ 	
/******/ 			var data = {};
/******/ 	
/******/ 			// Call dispose handlers
/******/ 			var disposeHandlers = module.hot._disposeHandlers;
/******/ 			for(var j = 0; j < disposeHandlers.length; j++) {
/******/ 				var cb = disposeHandlers[j];
/******/ 				cb(data);
/******/ 			}
/******/ 			hotCurrentModuleData[moduleId] = data;
/******/ 	
/******/ 			// disable module (this disables requires from this module)
/******/ 			module.hot.active = false;
/******/ 	
/******/ 			// remove module from cache
/******/ 			delete installedModules[moduleId];
/******/ 	
/******/ 			// remove "parents" references from all children
/******/ 			for(var j = 0; j < module.children.length; j++) {
/******/ 				var child = installedModules[module.children[j]];
/******/ 				if(!child) continue;
/******/ 				var idx = child.parents.indexOf(moduleId);
/******/ 				if(idx >= 0) {
/******/ 					child.parents.splice(idx, 1);
/******/ 				}
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// remove outdated dependency from module children
/******/ 		for(var moduleId in outdatedDependencies) {
/******/ 			if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
/******/ 				var module = installedModules[moduleId];
/******/ 				var moduleOutdatedDependencies = outdatedDependencies[moduleId];
/******/ 				for(var j = 0; j < moduleOutdatedDependencies.length; j++) {
/******/ 					var dependency = moduleOutdatedDependencies[j];
/******/ 					var idx = module.children.indexOf(dependency);
/******/ 					if(idx >= 0) module.children.splice(idx, 1);
/******/ 				}
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// Not in "apply" phase
/******/ 		hotSetStatus("apply");
/******/ 	
/******/ 		hotCurrentHash = hotUpdateNewHash;
/******/ 	
/******/ 		// insert new code
/******/ 		for(var moduleId in appliedUpdate) {
/******/ 			if(Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
/******/ 				modules[moduleId] = appliedUpdate[moduleId];
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// call accept handlers
/******/ 		var error = null;
/******/ 		for(var moduleId in outdatedDependencies) {
/******/ 			if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
/******/ 				var module = installedModules[moduleId];
/******/ 				var moduleOutdatedDependencies = outdatedDependencies[moduleId];
/******/ 				var callbacks = [];
/******/ 				for(var i = 0; i < moduleOutdatedDependencies.length; i++) {
/******/ 					var dependency = moduleOutdatedDependencies[i];
/******/ 					var cb = module.hot._acceptedDependencies[dependency];
/******/ 					if(callbacks.indexOf(cb) >= 0) continue;
/******/ 					callbacks.push(cb);
/******/ 				}
/******/ 				for(var i = 0; i < callbacks.length; i++) {
/******/ 					var cb = callbacks[i];
/******/ 					try {
/******/ 						cb(outdatedDependencies);
/******/ 					} catch(err) {
/******/ 						if(!error)
/******/ 							error = err;
/******/ 					}
/******/ 				}
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// Load self accepted modules
/******/ 		for(var i = 0; i < outdatedSelfAcceptedModules.length; i++) {
/******/ 			var item = outdatedSelfAcceptedModules[i];
/******/ 			var moduleId = item.module;
/******/ 			hotCurrentParents = [moduleId];
/******/ 			try {
/******/ 				__webpack_require__(moduleId);
/******/ 			} catch(err) {
/******/ 				if(typeof item.errorHandler === "function") {
/******/ 					try {
/******/ 						item.errorHandler(err);
/******/ 					} catch(err) {
/******/ 						if(!error)
/******/ 							error = err;
/******/ 					}
/******/ 				} else if(!error)
/******/ 					error = err;
/******/ 			}
/******/ 		}
/******/ 	
/******/ 		// handle errors in accept handlers and self accepted module load
/******/ 		if(error) {
/******/ 			hotSetStatus("fail");
/******/ 			return callback(error);
/******/ 		}
/******/ 	
/******/ 		hotSetStatus("idle");
/******/ 		callback(null, outdatedModules);
/******/ 	}

/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false,
/******/ 			hot: hotCreateModule(moduleId),
/******/ 			parents: hotCurrentParents,
/******/ 			children: []
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "build/";

/******/ 	// __webpack_hash__
/******/ 	__webpack_require__.h = function() { return hotCurrentHash; };

/******/ 	// Load entry module and return exports
/******/ 	return hotCreateRequire(0)(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__(1);


/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	/*export { default as ChromePicker } from './components/chrome/Chrome'
	export { default as CompactPicker } from './components/compact/Compact'
	export { default as MaterialPicker } from './components/material/Material'
	export { default as PhotoshopPicker } from './components/photoshop/Photoshop'
	export { default as SketchPicker } from './components/sketched/Sketch'*/

	//import { default as ColorPicker } from './components/customColor/Slider';
	//import { default as Alpha } from './components/customAlpha/Slider';

	var _Chrome = __webpack_require__(2);

	var _Chrome2 = _interopRequireDefault(_Chrome);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	//export SliderPicker
	/*export { default as SwatchesPicker } from './components/swatches/Swatches'
	export { default as CustomPicker } from './components/common/ColorWrap'*/

	//export default from './components/chrome/Chrome'

	//__LiteMolColorPicker.ColorPicker = ColorPicker;
	//__LiteMolColorPicker.AlphaPicker = Alpha;
	__LiteMolColorPicker.ChromePicker = _Chrome2.default;

/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.Chrome = undefined;

	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _common = __webpack_require__(15);

	var _ChromePointer = __webpack_require__(29);

	var _ChromePointer2 = _interopRequireDefault(_ChromePointer);

	var _ChromePointerCircle = __webpack_require__(30);

	var _ChromePointerCircle2 = _interopRequireDefault(_ChromePointerCircle);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	var _CompactColor = __webpack_require__(31);

	var _CompactColor2 = _interopRequireDefault(_CompactColor);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
	//import ChromeFields from '../customColor/SketchFields'


	var Chrome = exports.Chrome = function (_ReactCSS$Component) {
	  _inherits(Chrome, _ReactCSS$Component);

	  function Chrome() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, Chrome);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Chrome.__proto__ || Object.getPrototypeOf(Chrome)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _this.handleChange = function (data) {
	      _this.props.onChange(data);
	    }, _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(Chrome, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          picker: {
	            //background: '#fff',
	            //borderRadius: '2px',
	            //boxShadow: '0 0 2px rgba(0,0,0,.3), 0 4px 8px rgba(0,0,0,.3)',
	            //boxSizing: 'initial',
	            width: '100%'
	          },
	          saturation: {
	            width: '100%',
	            //paddingBottom: '35%',
	            //marginBottom: '1px',
	            height: '48px',
	            position: 'relative',
	            borderRadius: '0px',
	            overflow: 'hidden'
	          },
	          Saturation: {
	            radius: '0px'
	          },
	          body: {
	            padding: '0'
	          },
	          controls: {
	            marginTop: '1px',
	            display: 'block'
	          },
	          swatch: {
	            marginTop: '0px',
	            width: '16px',
	            height: '16px',
	            borderRadius: '8px',
	            position: 'relative',
	            overflow: 'hidden'
	          },
	          active: {
	            Absolute: '0 0 0 0',
	            zIndex: 2,
	            borderRadius: '8px',
	            boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.1)',
	            background: 'rgba(' + this.props.rgb.r + ', ' + this.props.rgb.g + ', ' + this.props.rgb.b + ', ' + this.props.rgb.a + ')'
	          },
	          hue: {
	            height: '16px',
	            position: 'relative',
	            width: '100%'
	          },
	          Hue: {
	            radius: '0'
	          },
	          colors: {
							marginTop: '1px',
	            display: 'flex',
	            flexDirection: 'row'
	          }
	          // fields: {
	          //   marginTop: '8px'
	          // }
	        }
	      };
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      var colors = [];
	      if (this.props.colors) {
	        for (var i = 0; i < this.props.colors.length; i++) {
	          var color = this.props.colors[i];
	          colors.push(_react2.default.createElement(_CompactColor2.default, { key: color, color: color, active: color.replace('#', '').toLowerCase() == this.props.hex, onClick: this.handleChange }));
	        }
	      }

	      return _react2.default.createElement(
	        'div',
	        { style: this.styles().picker },
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().saturation },
	          _react2.default.createElement(_common.Saturation, _extends({}, this.styles().Saturation, this.props, { pointer: _ChromePointerCircle2.default, onChange: this.handleChange }))
	        ),
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().body },
	          _react2.default.createElement(
	            'div',
	            { style: this.styles().hue },
	            _react2.default.createElement(_common.Hue, _extends({}, this.styles().Hue, this.props, { pointer: _ChromePointer2.default, onChange: this.handleChange }))
	          ),
	          _react2.default.createElement(
	            'div',
	            { style: this.styles().colors },
	            colors
	          )
	        )
	      );

	      // div style={ this.styles().toggles }>
	      //           <div style={ this.styles().hue }>
	      //             <Hue {...this.styles().Hue} {...this.props} pointer={ ChromePointer } onChange={ this.handleChange } />
	      //           </div>
	      //         </div>
	    }
	  }]);

	  return Chrome;
	}(_reactcss2.default.Component);

	Chrome.defaultProps = {
	  colors: ['#000000', '#808080', '#FFFFFF', '#D33115', '#E27300', '#FCC400', '#B0BC00', '#68BC00', '#16A5A5', '#009CE0', '#7B64FF', '#FA28FF', '#E20F2E']
	};

	exports.default = (0, _common.ColorWrap)(Chrome);

/***/ },
/* 3 */
/***/ function(module, exports) {

	'use strict';

	//exports['default'] = _libComponentsMove2['default'];
	module.exports = __LiteMolReact;


/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";module.exports={Component:__webpack_require__(5),inline:__webpack_require__(6),mixin:{css:__webpack_require__(6)}};

/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_get=function(e,t,r){for(var n=!0;n;){var o=e,i=t,c=r;n=!1,null===o&&(o=Function.prototype);var a=Object.getOwnPropertyDescriptor(o,i);if(void 0!==a){if("value"in a)return a.value;var u=a.get;if(void 0===u)return;return u.call(c)}var l=Object.getPrototypeOf(o);if(null===l)return;e=l,t=i,r=c,n=!0,a=l=void 0}},React=__webpack_require__(3),inline=__webpack_require__(6),ReactCSSComponent=function(e){function t(){_classCallCheck(this,t),_get(Object.getPrototypeOf(t.prototype),"constructor",this).apply(this,arguments)}return _inherits(t,e),_createClass(t,[{key:"css",value:function(e){return inline.call(this,e)}},{key:"styles",value:function(){return this.css()}}]),t}(React.Component);ReactCSSComponent.contextTypes={mixins:React.PropTypes.object},module.exports=ReactCSSComponent;

/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";var isObject=__webpack_require__(7),checkClassStructure=__webpack_require__(8),combine=__webpack_require__(9);module.exports=function(s){var e=this;combine=__webpack_require__(9);var r=[];if(!this.classes)throw console.warn("Define this.classes on `"+this.constructor.name+"`");checkClassStructure(this.classes());var t=function(s,t){e.classes()[s]?r.push(e.classes()[s]):s&&t&&t.warn===!0&&console.warn("The `"+s+"` css class does not exist on `"+e.constructor.name+"`")};t("default");for(var i in this.props){var c=this.props[i];isObject(c)||(c===!0?(t(i),t(i+"-true")):t(c?i+"-"+c:i+"-false"))}if(this.props&&this.props.activeBounds)for(var o=0;o<this.props.activeBounds.length;o++){var n=this.props.activeBounds[o];t(n)}for(var a in s){var u=s[a];u===!0&&t(a,{warn:!0})}var h={};return this.context&&this.context.mixins&&(h=this.context.mixins),combine(r,h)};

/***/ },
/* 7 */
/***/ function(module, exports) {

	/**
	 * lodash 3.0.2 (Custom Build) <https://lodash.com/>
	 * Build: `lodash modern modularize exports="npm" -o ./`
	 * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 * Available under MIT license <https://lodash.com/license>
	 */

	/**
	 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
	 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
	 *
	 * @static
	 * @memberOf _
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
	 * @example
	 *
	 * _.isObject({});
	 * // => true
	 *
	 * _.isObject([1, 2, 3]);
	 * // => true
	 *
	 * _.isObject(1);
	 * // => false
	 */
	function isObject(value) {
	  // Avoid a V8 JIT bug in Chrome 19-20.
	  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
	  var type = typeof value;
	  return !!value && (type == 'object' || type == 'function');
	}

	module.exports = isObject;


/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";var isObject=__webpack_require__(7);module.exports=function(e){for(var s in e){var o=e[s];if(isObject(o))for(var t in o){var a=o[t];isObject(a)||console.warn("Make sure the value of the element `"+s+"` is an object of css. You passed it `"+o+"`")}else console.warn("Make sure the value of `"+s+"` is an object of html elements. You passed it `"+o+"`")}};

/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";var merge=__webpack_require__(10),mixins=__webpack_require__(14);module.exports=function(r,e){var i=merge(r);return mixins(i,e)};

/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";var merge=__webpack_require__(11),isObject=__webpack_require__(7),isArray=__webpack_require__(13);module.exports=function(e){return isObject(e)&&!isArray(e)?e:1===e.length?e[0]:merge.recursive.apply(void 0,e)};

/***/ },
/* 11 */
/***/ function(module, exports, __webpack_require__) {

	/* WEBPACK VAR INJECTION */(function(module) {/*!
	 * @name JavaScript/NodeJS Merge v1.2.0
	 * @author yeikos
	 * @repository https://github.com/yeikos/js.merge

	 * Copyright 2014 yeikos - MIT license
	 * https://raw.github.com/yeikos/js.merge/master/LICENSE
	 */

	;(function(isNode) {

		/**
		 * Merge one or more objects 
		 * @param bool? clone
		 * @param mixed,... arguments
		 * @return object
		 */

		var Public = function(clone) {

			return merge(clone === true, false, arguments);

		}, publicName = 'merge';

		/**
		 * Merge two or more objects recursively 
		 * @param bool? clone
		 * @param mixed,... arguments
		 * @return object
		 */

		Public.recursive = function(clone) {

			return merge(clone === true, true, arguments);

		};

		/**
		 * Clone the input removing any reference
		 * @param mixed input
		 * @return mixed
		 */

		Public.clone = function(input) {

			var output = input,
				type = typeOf(input),
				index, size;

			if (type === 'array') {

				output = [];
				size = input.length;

				for (index=0;index<size;++index)

					output[index] = Public.clone(input[index]);

			} else if (type === 'object') {

				output = {};

				for (index in input)

					output[index] = Public.clone(input[index]);

			}

			return output;

		};

		/**
		 * Merge two objects recursively
		 * @param mixed input
		 * @param mixed extend
		 * @return mixed
		 */

		function merge_recursive(base, extend) {

			if (typeOf(base) !== 'object')

				return extend;

			for (var key in extend) {

				if (typeOf(base[key]) === 'object' && typeOf(extend[key]) === 'object') {

					base[key] = merge_recursive(base[key], extend[key]);

				} else {

					base[key] = extend[key];

				}

			}

			return base;

		}

		/**
		 * Merge two or more objects
		 * @param bool clone
		 * @param bool recursive
		 * @param array argv
		 * @return object
		 */

		function merge(clone, recursive, argv) {

			var result = argv[0],
				size = argv.length;

			if (clone || typeOf(result) !== 'object')

				result = {};

			for (var index=0;index<size;++index) {

				var item = argv[index],

					type = typeOf(item);

				if (type !== 'object') continue;

				for (var key in item) {

					var sitem = clone ? Public.clone(item[key]) : item[key];

					if (recursive) {

						result[key] = merge_recursive(result[key], sitem);

					} else {

						result[key] = sitem;

					}

				}

			}

			return result;

		}

		/**
		 * Get type of variable
		 * @param mixed input
		 * @return string
		 *
		 * @see http://jsperf.com/typeofvar
		 */

		function typeOf(input) {

			return ({}).toString.call(input).slice(8, -1).toLowerCase();

		}

		if (isNode) {

			module.exports = Public;

		} else {

			window[publicName] = Public;

		}

	})(typeof module === 'object' && module && typeof module.exports === 'object' && module.exports);
	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12)(module)))

/***/ },
/* 12 */
/***/ function(module, exports) {

	module.exports = function(module) {
		if(!module.webpackPolyfill) {
			module.deprecate = function() {};
			module.paths = [];
			// module.parent = undefined by default
			module.children = [];
			module.webpackPolyfill = 1;
		}
		return module;
	}


/***/ },
/* 13 */
/***/ function(module, exports) {

	/**
	 * lodash 4.0.0 (Custom Build) <https://lodash.com/>
	 * Build: `lodash modularize exports="npm" -o ./`
	 * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 * Available under MIT license <https://lodash.com/license>
	 */

	/**
	 * Checks if `value` is classified as an `Array` object.
	 *
	 * @static
	 * @memberOf _
	 * @type Function
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
	 * @example
	 *
	 * _.isArray([1, 2, 3]);
	 * // => true
	 *
	 * _.isArray(document.body.children);
	 * // => false
	 *
	 * _.isArray('abc');
	 * // => false
	 *
	 * _.isArray(_.noop);
	 * // => false
	 */
	var isArray = Array.isArray;

	module.exports = isArray;


/***/ },
/* 14 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";var isObject=__webpack_require__(7),isArray=__webpack_require__(13),merge=__webpack_require__(11),localProps={borderRadius:function(r){return null!==r?{msBorderRadius:r,MozBorderRadius:r,OBorderRadius:r,WebkitBorderRadius:r,borderRadius:r}:void 0},boxShadow:function(r){return null!==r?{msBoxShadow:r,MozBoxShadow:r,OBoxShadow:r,WebkitBoxShadow:r,boxShadow:r}:void 0},userSelect:function(r){return null!==r?{WebkitTouchCallout:r,KhtmlUserSelect:r,MozUserSelect:r,msUserSelect:r,WebkitUserSelect:r,userSelect:r}:void 0},flex:function(r){return null!==r?{WebkitBoxFlex:r,MozBoxFlex:r,WebkitFlex:r,msFlex:r,flex:r}:void 0},flexBasis:function(r){return null!==r?{WebkitFlexBasis:r,flexBasis:r}:void 0},justifyContent:function(r){return null!==r?{WebkitJustifyContent:r,justifyContent:r}:void 0},transition:function(r){return null!==r?{msTransition:r,MozTransition:r,OTransition:r,WebkitTransition:r,transition:r}:void 0},transform:function(r){return null!==r?{msTransform:r,MozTransform:r,OTransform:r,WebkitTransform:r,transform:r}:void 0},Absolute:function(r){if(null!==r){var e=r.split(" ");return{position:"absolute",top:e[0],right:e[1],bottom:e[2],left:e[3]}}},Extend:function(r,e){var o=e[r];return o?o:void 0}},transform=function r(e,o,t){var n=merge(o,localProps),i={};for(var s in e){var u=e[s];if(isObject(u)&&!isArray(u))i[s]=r(u,o,e);else if(n[s]){var l=n[s](u,t);for(var a in l){var f=l[a];i[a]=f}}else i[s]=u}return i};module.exports=function(r,e,o){return transform(r,e,o)};

/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});

	var _Alpha = __webpack_require__(16);

	Object.defineProperty(exports, 'Alpha', {
	  enumerable: true,
	  get: function get() {
	    return _interopRequireDefault(_Alpha).default;
	  }
	});

	var _Checkboard = __webpack_require__(20);

	Object.defineProperty(exports, 'Checkboard', {
	  enumerable: true,
	  get: function get() {
	    return _interopRequireDefault(_Checkboard).default;
	  }
	});

	var _Hue = __webpack_require__(21);

	Object.defineProperty(exports, 'Hue', {
	  enumerable: true,
	  get: function get() {
	    return _interopRequireDefault(_Hue).default;
	  }
	});

	var _Saturation = __webpack_require__(22);

	Object.defineProperty(exports, 'Saturation', {
	  enumerable: true,
	  get: function get() {
	    return _interopRequireDefault(_Saturation).default;
	  }
	});

	var _ColorWrap = __webpack_require__(24);

	Object.defineProperty(exports, 'ColorWrap', {
	  enumerable: true,
	  get: function get() {
	    return _interopRequireDefault(_ColorWrap).default;
	  }
	});

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.Alpha = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	var _Checkboard = __webpack_require__(20);

	var _Checkboard2 = _interopRequireDefault(_Checkboard);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var Alpha = exports.Alpha = function (_ReactCSS$Component) {
	  _inherits(Alpha, _ReactCSS$Component);

	  function Alpha() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, Alpha);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Alpha.__proto__ || Object.getPrototypeOf(Alpha)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _this.handleChange = function (e, skip) {
	      !skip && e.preventDefault();
	      var container = _this.refs.container;
	      var containerWidth = container.clientWidth;
	      var left = (e.pageX || e.touches[0].pageX) - (container.getBoundingClientRect().left + window.pageXOffset);

	      var a;
	      if (left < 0) {
	        a = 0;
	      } else if (left > containerWidth) {
	        a = 1;
	      } else {
	        a = Math.round(left * 100 / containerWidth) / 100;
	      }

	      if (_this.props.a !== a) {
	        _this.props.onChange({
	          h: _this.props.hsl.h,
	          s: _this.props.hsl.s,
	          l: _this.props.hsl.l,
	          a: a,
	          source: 'rgb'
	        });
	      }
	    }, _this.handleMouseDown = function (e) {
	      _this.handleChange(e, true);
	      window.addEventListener('mousemove', _this.handleChange);
	      window.addEventListener('mouseup', _this.handleMouseUp);
	    }, _this.handleMouseUp = function () {
	      _this.unbindEventListeners();
	    }, _this.unbindEventListeners = function () {
	      window.removeEventListener('mousemove', _this.handleChange);
	      window.removeEventListener('mouseup', _this.handleMouseUp);
	    }, _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(Alpha, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          alpha: {
	            Absolute: '0 0 0 0',
	            borderRadius: this.props.radius
	          },
	          checkboard: {
	            Absolute: '0 0 0 0',
	            overflow: 'hidden'
	          },
	          gradient: {
	            Absolute: '0 0 0 0',
	            background: 'linear-gradient(to right, rgba(' + this.props.rgb.r + ', ' + this.props.rgb.g + ', ' + this.props.rgb.b + ', 0) 0%, rgba(' + this.props.rgb.r + ', ' + this.props.rgb.g + ', ' + this.props.rgb.b + ', 1) 100%)',
	            boxShadow: this.props.shadow,
	            borderRadius: this.props.radius
	          },
	          container: {
	            position: 'relative',
	            zIndex: '2',
	            height: '100%',
	            margin: '0 3px'
	          },
	          pointer: {
	            zIndex: '2',
	            position: 'absolute',
	            left: this.props.rgb.a * 100 + '%'
	          },
	          slider: {
	            width: '4px',
	            borderRadius: '1px',
	            height: '8px',
	            boxShadow: '0 0 2px rgba(0, 0, 0, .6)',
	            background: '#fff',
	            marginTop: '1px',
	            transform: 'translateX(-2px)'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'componentWillUnmount',
	    value: function componentWillUnmount() {
	      this.unbindEventListeners();
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      var pointer = _react2.default.createElement('div', { style: this.styles().slider });

	      if (this.props.pointer) {
	        pointer = _react2.default.createElement(this.props.pointer, this.props);
	      }

	      return _react2.default.createElement(
	        'div',
	        { style: this.styles().alpha },
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().checkboard },
	          _react2.default.createElement(_Checkboard2.default, null)
	        ),
	        _react2.default.createElement('div', { style: this.styles().gradient }),
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().container, ref: 'container', onMouseDown: this.handleMouseDown,
	            onTouchMove: this.handleChange,
	            onTouchStart: this.handleChange },
	          _react2.default.createElement(
	            'div',
	            { style: this.styles().pointer, ref: 'pointer' },
	            pointer
	          )
	        )
	      );
	    }
	  }]);

	  return Alpha;
	}(_reactcss2.default.Component);

	exports.default = Alpha;

/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__(18);

/***/ },
/* 18 */
/***/ function(module, exports, __webpack_require__) {

	/**
	 * Copyright 2013-2015, Facebook, Inc.
	 * All rights reserved.
	 *
	 * This source code is licensed under the BSD-style license found in the
	 * LICENSE file in the root directory of this source tree. An additional grant
	 * of patent rights can be found in the PATENTS file in the same directory.
	 *
	* @providesModule shallowCompare
	*/

	'use strict';

	var shallowEqual = __webpack_require__(19);

	/**
	 * Does a shallow comparison for props and state.
	 * See ReactComponentWithPureRenderMixin
	 */
	function shallowCompare(instance, nextProps, nextState) {
	  return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
	}

	module.exports = shallowCompare;

/***/ },
/* 19 */
/***/ function(module, exports) {

	/**
	 * Copyright 2013-2015, Facebook, Inc.
	 * All rights reserved.
	 *
	 * This source code is licensed under the BSD-style license found in the
	 * LICENSE file in the root directory of this source tree. An additional grant
	 * of patent rights can be found in the PATENTS file in the same directory.
	 *
	 * @providesModule shallowEqual
	 * @typechecks
	 * 
	 */

	'use strict';

	var hasOwnProperty = Object.prototype.hasOwnProperty;

	/**
	 * Performs equality by iterating through keys on an object and returning false
	 * when any key has values which are not strictly equal between the arguments.
	 * Returns true when the values of all keys are strictly equal.
	 */
	function shallowEqual(objA, objB) {
	  if (objA === objB) {
	    return true;
	  }

	  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
	    return false;
	  }

	  var keysA = Object.keys(objA);
	  var keysB = Object.keys(objB);

	  if (keysA.length !== keysB.length) {
	    return false;
	  }

	  // Test for A's keys different from B.
	  var bHasOwnProperty = hasOwnProperty.bind(objB);
	  for (var i = 0; i < keysA.length; i++) {
	    if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
	      return false;
	    }
	  }

	  return true;
	}

	module.exports = shallowEqual;

/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.Checkboard = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var _checkboardCache = {};

	function renderCheckboard(c1, c2, size) {
	  if (typeof document == 'undefined') return null; // Dont Render On Server
	  var canvas = document.createElement('canvas');
	  canvas.width = canvas.height = size * 2;
	  var ctx = canvas.getContext('2d');
	  if (!ctx) return null; // If no context can be found, return early.
	  ctx.fillStyle = c1;
	  ctx.fillRect(0, 0, canvas.width, canvas.height);
	  ctx.fillStyle = c2;
	  ctx.fillRect(0, 0, size, size);
	  ctx.translate(size, size);
	  ctx.fillRect(0, 0, size, size);
	  return canvas.toDataURL();
	}

	function getCheckboard(c1, c2, size) {
	  var key = c1 + ',' + c2 + ',' + size;

	  if (_checkboardCache[key]) {
	    return _checkboardCache[key];
	  } else {
	    var checkboard = renderCheckboard(c1, c2, size);
	    _checkboardCache[key] = checkboard;
	    return checkboard;
	  }
	}

	var Checkboard = exports.Checkboard = function (_ReactCSS$Component) {
	  _inherits(Checkboard, _ReactCSS$Component);

	  function Checkboard() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, Checkboard);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Checkboard.__proto__ || Object.getPrototypeOf(Checkboard)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(Checkboard, [{
	    key: 'classes',
	    value: function classes() {
	      var background = getCheckboard(this.props.white, this.props.grey, this.props.size);
	      return {
	        'default': {
	          grid: {
	            Absolute: '0 0 0 0',
	            background: 'url(' + background + ') center left'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      return _react2.default.createElement('div', { style: this.styles().grid, ref: 'grid' });
	    }
	  }]);

	  return Checkboard;
	}(_reactcss2.default.Component);

	Checkboard.defaultProps = {
	  size: 8,
	  white: '#fff',
	  grey: '#e6e6e6'
	};

	exports.default = Checkboard;

/***/ },
/* 21 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.Hue = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var Hue = exports.Hue = function (_ReactCSS$Component) {
	  _inherits(Hue, _ReactCSS$Component);

	  function Hue() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, Hue);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Hue.__proto__ || Object.getPrototypeOf(Hue)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _this.handleChange = function (e, skip) {
	      !skip && e.preventDefault();
	      var container = _this.refs.container;
	      var containerWidth = container.clientWidth;
	      var containerHeight = container.clientHeight;
	      var left = (e.pageX || e.touches && e.touches[0].pageX || 0) - (container.getBoundingClientRect().left + window.pageXOffset);
	      var top = (e.pageY || e.touches && e.touches[0].pageY || 0) - (container.getBoundingClientRect().top + window.pageYOffset);

	      if (_this.props.direction === 'vertical') {
	        var h;
	        if (top < 0) {
	          h = 359;
	        } else if (top > containerHeight) {
	          h = 0;
	        } else {
	          var percent = -(top * 100 / containerHeight) + 100;
	          h = 360 * percent / 100;
	        }

	        if (_this.props.hsl.h !== h) {
	          _this.props.onChange({
	            h: h,
	            s: _this.props.hsl.s,
	            l: _this.props.hsl.l,
	            a: _this.props.hsl.a,
	            source: 'rgb'
	          });
	        }
	      } else {
	        var h;
	        if (left < 0) {
	          h = 0;
	        } else if (left > containerWidth) {
	          h = 359;
	        } else {
	          var percent = left * 100 / containerWidth;
	          h = 360 * percent / 100;
	        }

	        if (_this.props.hsl.h !== h) {
	          _this.props.onChange({
	            h: h,
	            s: _this.props.hsl.s,
	            l: _this.props.hsl.l,
	            a: _this.props.hsl.a,
	            source: 'rgb'
	          });
	        }
	      }
	    }, _this.handleMouseDown = function (e) {
	      _this.handleChange(e, true);
	      window.addEventListener('mousemove', _this.handleChange);
	      window.addEventListener('mouseup', _this.handleMouseUp);
	    }, _this.handleMouseUp = function () {
	      _this.unbindEventListeners();
	    }, _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(Hue, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          hue: {
	            Absolute: '0 0 0 0',
	            background: 'linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)',
	            borderRadius: this.props.radius,
	            boxShadow: this.props.shadow
	          },
	          container: {
	            margin: '0 2px',
	            position: 'relative',
	            height: '100%'
	          },
	          pointer: {
	            zIndex: '2',
	            position: 'absolute',
	            left: this.props.hsl.h * 100 / 360 + '%'
	          },
	          slider: {
	            marginTop: '1px',
	            width: '4px',
	            borderRadius: '1px',
	            height: '8px',
	            boxShadow: '0 0 2px rgba(0, 0, 0, .6)',
	            background: '#fff',
	            transform: 'translateX(-2px)'
	          }
	        },
	        'direction-vertical': {
	          hue: {
	            background: 'linear-gradient(to top, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)'
	          },
	          pointer: {
	            left: '0',
	            top: -(this.props.hsl.h * 100 / 360) + 100 + '%'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'componentWillUnmount',
	    value: function componentWillUnmount() {
	      this.unbindEventListeners();
	    }
	  }, {
	    key: 'unbindEventListeners',
	    value: function unbindEventListeners() {
	      window.removeEventListener('mousemove', this.handleChange);
	      window.removeEventListener('mouseup', this.handleMouseUp);
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      var pointer = _react2.default.createElement('div', { style: this.styles().slider });

	      if (this.props.pointer) {
	        pointer = _react2.default.createElement(this.props.pointer, this.props);
	      }

	      return _react2.default.createElement(
	        'div',
	        { style: this.styles().hue },
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().container, ref: 'container', onMouseDown: this.handleMouseDown,
	            onTouchMove: this.handleChange,
	            onTouchStart: this.handleChange },
	          _react2.default.createElement(
	            'div',
	            { style: this.styles().pointer, ref: 'pointer' },
	            pointer
	          )
	        )
	      );
	    }
	  }]);

	  return Hue;
	}(_reactcss2.default.Component);

	exports.default = Hue;

/***/ },
/* 22 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.Saturation = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _lodash = __webpack_require__(23);

	var _lodash2 = _interopRequireDefault(_lodash);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var Saturation = exports.Saturation = function (_ReactCSS$Component) {
	  _inherits(Saturation, _ReactCSS$Component);

	  function Saturation(props) {
	    _classCallCheck(this, Saturation);

	    var _this = _possibleConstructorReturn(this, (Saturation.__proto__ || Object.getPrototypeOf(Saturation)).call(this));

	    _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]);

	    _this.handleChange = function (e, skip) {
	      !skip && e.preventDefault();
	      var container = _this.refs.container;
	      var containerWidth = container.clientWidth;
	      var containerHeight = container.clientHeight;
	      var left = (e.pageX || e.touches[0].pageX) - (container.getBoundingClientRect().left + window.pageXOffset);
	      var top = (e.pageY || e.touches[0].pageY) - (container.getBoundingClientRect().top + window.pageYOffset);

	      if (left < 0) {
	        left = 0;
	      } else if (left > containerWidth) {
	        left = containerWidth;
	      } else if (top < 0) {
	        top = 0;
	      } else if (top > containerHeight) {
	        top = containerHeight;
	      }

	      var saturation = left * 100 / containerWidth;
	      var bright = -(top * 100 / containerHeight) + 100;

	      _this.throttle(_this.props.onChange, {
	        h: _this.props.hsl.h,
	        s: saturation,
	        v: bright,
	        a: _this.props.hsl.a,
	        source: 'rgb'
	      });
	    };

	    _this.handleMouseDown = function (e) {
	      _this.handleChange(e, true);
	      window.addEventListener('mousemove', _this.handleChange);
	      window.addEventListener('mouseup', _this.handleMouseUp);
	    };

	    _this.handleMouseUp = function () {
	      _this.unbindEventListeners();
	    };

	    _this.throttle = (0, _lodash2.default)(function (fn, data) {
	      fn(data);
	    }, 50);
	    return _this;
	  }

	  _createClass(Saturation, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          color: {
	            Absolute: '0 0 0 0',
	            background: 'hsl(' + this.props.hsl.h + ',100%, 50%)',
	            borderRadius: this.props.radius
	          },
	          white: {
	            Absolute: '0 0 0 0',
	            background: 'linear-gradient(to right, #fff, rgba(255,255,255,0))'
	          },
	          black: {
	            Absolute: '0 0 0 0',
	            background: 'linear-gradient(to top, #000, rgba(0,0,0,0))',
	            boxShadow: this.props.shadow
	          },
	          pointer: {
	            position: 'absolute',
	            top: -(this.props.hsv.v * 100) + 100 + '%',
	            left: this.props.hsv.s * 100 + '%',
	            cursor: 'default'
	          },
	          circle: {
	            width: '4px',
	            height: '4px',
	            boxShadow: '0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0,0,0,.3), 0 0 1px 2px rgba(0,0,0,.4)',
	            borderRadius: '50%',
	            cursor: 'hand',
	            transform: 'translate(-2px, -2px)'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'componentWillUnmount',
	    value: function componentWillUnmount() {
	      this.unbindEventListeners();
	    }
	  }, {
	    key: 'unbindEventListeners',
	    value: function unbindEventListeners() {
	      window.removeEventListener('mousemove', this.handleChange);
	      window.removeEventListener('mouseup', this.handleMouseUp);
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      var pointer = _react2.default.createElement('div', { style: this.styles().circle });

	      if (this.props.pointer) {
	        pointer = _react2.default.createElement(this.props.pointer, this.props);
	      }

	      return _react2.default.createElement(
	        'div',
	        { style: this.styles().color, ref: 'container', onMouseDown: this.handleMouseDown,
	          onTouchMove: this.handleChange,
	          onTouchStart: this.handleChange },
	        _react2.default.createElement(
	          'div',
	          { style: this.styles().white },
	          _react2.default.createElement('div', { style: this.styles().black }),
	          _react2.default.createElement(
	            'div',
	            { style: this.styles().pointer, ref: 'pointer' },
	            pointer
	          )
	        )
	      );
	    }
	  }]);

	  return Saturation;
	}(_reactcss2.default.Component);

	exports.default = Saturation;

/***/ },
/* 23 */
/***/ function(module, exports) {

	/* WEBPACK VAR INJECTION */(function(global) {/**
	 * lodash (Custom Build) <https://lodash.com/>
	 * Build: `lodash modularize exports="npm" -o ./`
	 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
	 * Released under MIT license <https://lodash.com/license>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 */

	/** Used as the `TypeError` message for "Functions" methods. */
	var FUNC_ERROR_TEXT = 'Expected a function';

	/** Used as references for various `Number` constants. */
	var NAN = 0 / 0;

	/** `Object#toString` result references. */
	var symbolTag = '[object Symbol]';

	/** Used to match leading and trailing whitespace. */
	var reTrim = /^\s+|\s+$/g;

	/** Used to detect bad signed hexadecimal string values. */
	var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

	/** Used to detect binary string values. */
	var reIsBinary = /^0b[01]+$/i;

	/** Used to detect octal string values. */
	var reIsOctal = /^0o[0-7]+$/i;

	/** Built-in method references without a dependency on `root`. */
	var freeParseInt = parseInt;

	/** Detect free variable `global` from Node.js. */
	var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;

	/** Detect free variable `self`. */
	var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

	/** Used as a reference to the global object. */
	var root = freeGlobal || freeSelf || Function('return this')();

	/** Used for built-in method references. */
	var objectProto = Object.prototype;

	/**
	 * Used to resolve the
	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
	 * of values.
	 */
	var objectToString = objectProto.toString;

	/* Built-in method references for those with the same name as other `lodash` methods. */
	var nativeMax = Math.max,
	    nativeMin = Math.min;

	/**
	 * Gets the timestamp of the number of milliseconds that have elapsed since
	 * the Unix epoch (1 January 1970 00:00:00 UTC).
	 *
	 * @static
	 * @memberOf _
	 * @since 2.4.0
	 * @category Date
	 * @returns {number} Returns the timestamp.
	 * @example
	 *
	 * _.defer(function(stamp) {
	 *   console.log(_.now() - stamp);
	 * }, _.now());
	 * // => Logs the number of milliseconds it took for the deferred invocation.
	 */
	var now = function() {
	  return root.Date.now();
	};

	/**
	 * Creates a debounced function that delays invoking `func` until after `wait`
	 * milliseconds have elapsed since the last time the debounced function was
	 * invoked. The debounced function comes with a `cancel` method to cancel
	 * delayed `func` invocations and a `flush` method to immediately invoke them.
	 * Provide `options` to indicate whether `func` should be invoked on the
	 * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
	 * with the last arguments provided to the debounced function. Subsequent
	 * calls to the debounced function return the result of the last `func`
	 * invocation.
	 *
	 * **Note:** If `leading` and `trailing` options are `true`, `func` is
	 * invoked on the trailing edge of the timeout only if the debounced function
	 * is invoked more than once during the `wait` timeout.
	 *
	 * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
	 * until to the next tick, similar to `setTimeout` with a timeout of `0`.
	 *
	 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
	 * for details over the differences between `_.debounce` and `_.throttle`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Function
	 * @param {Function} func The function to debounce.
	 * @param {number} [wait=0] The number of milliseconds to delay.
	 * @param {Object} [options={}] The options object.
	 * @param {boolean} [options.leading=false]
	 *  Specify invoking on the leading edge of the timeout.
	 * @param {number} [options.maxWait]
	 *  The maximum time `func` is allowed to be delayed before it's invoked.
	 * @param {boolean} [options.trailing=true]
	 *  Specify invoking on the trailing edge of the timeout.
	 * @returns {Function} Returns the new debounced function.
	 * @example
	 *
	 * // Avoid costly calculations while the window size is in flux.
	 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
	 *
	 * // Invoke `sendMail` when clicked, debouncing subsequent calls.
	 * jQuery(element).on('click', _.debounce(sendMail, 300, {
	 *   'leading': true,
	 *   'trailing': false
	 * }));
	 *
	 * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
	 * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
	 * var source = new EventSource('/stream');
	 * jQuery(source).on('message', debounced);
	 *
	 * // Cancel the trailing debounced invocation.
	 * jQuery(window).on('popstate', debounced.cancel);
	 */
	function debounce(func, wait, options) {
	  var lastArgs,
	      lastThis,
	      maxWait,
	      result,
	      timerId,
	      lastCallTime,
	      lastInvokeTime = 0,
	      leading = false,
	      maxing = false,
	      trailing = true;

	  if (typeof func != 'function') {
	    throw new TypeError(FUNC_ERROR_TEXT);
	  }
	  wait = toNumber(wait) || 0;
	  if (isObject(options)) {
	    leading = !!options.leading;
	    maxing = 'maxWait' in options;
	    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
	    trailing = 'trailing' in options ? !!options.trailing : trailing;
	  }

	  function invokeFunc(time) {
	    var args = lastArgs,
	        thisArg = lastThis;

	    lastArgs = lastThis = undefined;
	    lastInvokeTime = time;
	    result = func.apply(thisArg, args);
	    return result;
	  }

	  function leadingEdge(time) {
	    // Reset any `maxWait` timer.
	    lastInvokeTime = time;
	    // Start the timer for the trailing edge.
	    timerId = setTimeout(timerExpired, wait);
	    // Invoke the leading edge.
	    return leading ? invokeFunc(time) : result;
	  }

	  function remainingWait(time) {
	    var timeSinceLastCall = time - lastCallTime,
	        timeSinceLastInvoke = time - lastInvokeTime,
	        result = wait - timeSinceLastCall;

	    return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
	  }

	  function shouldInvoke(time) {
	    var timeSinceLastCall = time - lastCallTime,
	        timeSinceLastInvoke = time - lastInvokeTime;

	    // Either this is the first call, activity has stopped and we're at the
	    // trailing edge, the system time has gone backwards and we're treating
	    // it as the trailing edge, or we've hit the `maxWait` limit.
	    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
	      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
	  }

	  function timerExpired() {
	    var time = now();
	    if (shouldInvoke(time)) {
	      return trailingEdge(time);
	    }
	    // Restart the timer.
	    timerId = setTimeout(timerExpired, remainingWait(time));
	  }

	  function trailingEdge(time) {
	    timerId = undefined;

	    // Only invoke if we have `lastArgs` which means `func` has been
	    // debounced at least once.
	    if (trailing && lastArgs) {
	      return invokeFunc(time);
	    }
	    lastArgs = lastThis = undefined;
	    return result;
	  }

	  function cancel() {
	    if (timerId !== undefined) {
	      clearTimeout(timerId);
	    }
	    lastInvokeTime = 0;
	    lastArgs = lastCallTime = lastThis = timerId = undefined;
	  }

	  function flush() {
	    return timerId === undefined ? result : trailingEdge(now());
	  }

	  function debounced() {
	    var time = now(),
	        isInvoking = shouldInvoke(time);

	    lastArgs = arguments;
	    lastThis = this;
	    lastCallTime = time;

	    if (isInvoking) {
	      if (timerId === undefined) {
	        return leadingEdge(lastCallTime);
	      }
	      if (maxing) {
	        // Handle invocations in a tight loop.
	        timerId = setTimeout(timerExpired, wait);
	        return invokeFunc(lastCallTime);
	      }
	    }
	    if (timerId === undefined) {
	      timerId = setTimeout(timerExpired, wait);
	    }
	    return result;
	  }
	  debounced.cancel = cancel;
	  debounced.flush = flush;
	  return debounced;
	}

	/**
	 * Creates a throttled function that only invokes `func` at most once per
	 * every `wait` milliseconds. The throttled function comes with a `cancel`
	 * method to cancel delayed `func` invocations and a `flush` method to
	 * immediately invoke them. Provide `options` to indicate whether `func`
	 * should be invoked on the leading and/or trailing edge of the `wait`
	 * timeout. The `func` is invoked with the last arguments provided to the
	 * throttled function. Subsequent calls to the throttled function return the
	 * result of the last `func` invocation.
	 *
	 * **Note:** If `leading` and `trailing` options are `true`, `func` is
	 * invoked on the trailing edge of the timeout only if the throttled function
	 * is invoked more than once during the `wait` timeout.
	 *
	 * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
	 * until to the next tick, similar to `setTimeout` with a timeout of `0`.
	 *
	 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
	 * for details over the differences between `_.throttle` and `_.debounce`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Function
	 * @param {Function} func The function to throttle.
	 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
	 * @param {Object} [options={}] The options object.
	 * @param {boolean} [options.leading=true]
	 *  Specify invoking on the leading edge of the timeout.
	 * @param {boolean} [options.trailing=true]
	 *  Specify invoking on the trailing edge of the timeout.
	 * @returns {Function} Returns the new throttled function.
	 * @example
	 *
	 * // Avoid excessively updating the position while scrolling.
	 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
	 *
	 * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
	 * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
	 * jQuery(element).on('click', throttled);
	 *
	 * // Cancel the trailing throttled invocation.
	 * jQuery(window).on('popstate', throttled.cancel);
	 */
	function throttle(func, wait, options) {
	  var leading = true,
	      trailing = true;

	  if (typeof func != 'function') {
	    throw new TypeError(FUNC_ERROR_TEXT);
	  }
	  if (isObject(options)) {
	    leading = 'leading' in options ? !!options.leading : leading;
	    trailing = 'trailing' in options ? !!options.trailing : trailing;
	  }
	  return debounce(func, wait, {
	    'leading': leading,
	    'maxWait': wait,
	    'trailing': trailing
	  });
	}

	/**
	 * Checks if `value` is the
	 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
	 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
	 * @example
	 *
	 * _.isObject({});
	 * // => true
	 *
	 * _.isObject([1, 2, 3]);
	 * // => true
	 *
	 * _.isObject(_.noop);
	 * // => true
	 *
	 * _.isObject(null);
	 * // => false
	 */
	function isObject(value) {
	  var type = typeof value;
	  return !!value && (type == 'object' || type == 'function');
	}

	/**
	 * Checks if `value` is object-like. A value is object-like if it's not `null`
	 * and has a `typeof` result of "object".
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
	 * @example
	 *
	 * _.isObjectLike({});
	 * // => true
	 *
	 * _.isObjectLike([1, 2, 3]);
	 * // => true
	 *
	 * _.isObjectLike(_.noop);
	 * // => false
	 *
	 * _.isObjectLike(null);
	 * // => false
	 */
	function isObjectLike(value) {
	  return !!value && typeof value == 'object';
	}

	/**
	 * Checks if `value` is classified as a `Symbol` primitive or object.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
	 * @example
	 *
	 * _.isSymbol(Symbol.iterator);
	 * // => true
	 *
	 * _.isSymbol('abc');
	 * // => false
	 */
	function isSymbol(value) {
	  return typeof value == 'symbol' ||
	    (isObjectLike(value) && objectToString.call(value) == symbolTag);
	}

	/**
	 * Converts `value` to a number.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to process.
	 * @returns {number} Returns the number.
	 * @example
	 *
	 * _.toNumber(3.2);
	 * // => 3.2
	 *
	 * _.toNumber(Number.MIN_VALUE);
	 * // => 5e-324
	 *
	 * _.toNumber(Infinity);
	 * // => Infinity
	 *
	 * _.toNumber('3.2');
	 * // => 3.2
	 */
	function toNumber(value) {
	  if (typeof value == 'number') {
	    return value;
	  }
	  if (isSymbol(value)) {
	    return NAN;
	  }
	  if (isObject(value)) {
	    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
	    value = isObject(other) ? (other + '') : other;
	  }
	  if (typeof value != 'string') {
	    return value === 0 ? value : +value;
	  }
	  value = value.replace(reTrim, '');
	  var isBinary = reIsBinary.test(value);
	  return (isBinary || reIsOctal.test(value))
	    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
	    : (reIsBadHex.test(value) ? NAN : +value);
	}

	module.exports = throttle;

	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))

/***/ },
/* 24 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.ColorWrap = undefined;

	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _merge = __webpack_require__(11);

	var _merge2 = _interopRequireDefault(_merge);

	var _lodash = __webpack_require__(25);

	var _lodash2 = _interopRequireDefault(_lodash);

	var _lodash3 = __webpack_require__(26);

	var _lodash4 = _interopRequireDefault(_lodash3);

	var _color = __webpack_require__(27);

	var _color2 = _interopRequireDefault(_color);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var ColorWrap = exports.ColorWrap = function ColorWrap(Picker) {
	  var ColorPicker = function (_React$Component) {
	    _inherits(ColorPicker, _React$Component);

	    function ColorPicker(props) {
	      _classCallCheck(this, ColorPicker);

	      var _this = _possibleConstructorReturn(this, (ColorPicker.__proto__ || Object.getPrototypeOf(ColorPicker)).call(this));

	      _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]);

	      _this.handleChange = function (data) {
	        data = _color2.default.simpleCheckForValidColor(data);
	        if (data) {
	          var colors = _color2.default.toState(data, data.h || _this.state.oldHue);
	          _this.setState(colors);
	          _this.props.onChangeComplete && _this.debounce(_this.props.onChangeComplete, colors);
	          _this.props.onChange && _this.props.onChange(colors);
	        }
	      };

	      _this.state = (0, _merge2.default)(_color2.default.toState(props.color, 0), {
	        visible: props.display
	      });

	      _this.debounce = (0, _lodash4.default)(function (fn, data) {
	        fn(data);
	      }, 100);
	      return _this;
	    }

	    _createClass(ColorPicker, [{
	      key: 'componentWillReceiveProps',
	      value: function componentWillReceiveProps(nextProps) {
	        this.setState((0, _merge2.default)(_color2.default.toState(nextProps.color, this.state.oldHue), {
	          visible: nextProps.display
	        }));
	      }
	    }, {
	      key: 'render',
	      value: function render() {
	        return _react2.default.createElement(Picker, _extends({}, this.props, this.state, { onChange: this.handleChange }));
	      }
	    }]);

	    return ColorPicker;
	  }(_react2.default.Component);

	  ColorPicker.defaultProps = {
	    color: {
	      h: 250,
	      s: .50,
	      l: .20,
	      a: 1
	    }
	  };

	  return ColorPicker;
	};

	exports.default = ColorWrap;

/***/ },
/* 25 */
/***/ function(module, exports) {

	/**
	 * lodash (Custom Build) <https://lodash.com/>
	 * Build: `lodash modularize exports="npm" -o ./`
	 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
	 * Released under MIT license <https://lodash.com/license>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 */

	/** `Object#toString` result references. */
	var objectTag = '[object Object]';

	/**
	 * Checks if `value` is a host object in IE < 9.
	 *
	 * @private
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
	 */
	function isHostObject(value) {
	  // Many host objects are `Object` objects that can coerce to strings
	  // despite having improperly defined `toString` methods.
	  var result = false;
	  if (value != null && typeof value.toString != 'function') {
	    try {
	      result = !!(value + '');
	    } catch (e) {}
	  }
	  return result;
	}

	/**
	 * Creates a unary function that invokes `func` with its argument transformed.
	 *
	 * @private
	 * @param {Function} func The function to wrap.
	 * @param {Function} transform The argument transform.
	 * @returns {Function} Returns the new function.
	 */
	function overArg(func, transform) {
	  return function(arg) {
	    return func(transform(arg));
	  };
	}

	/** Used for built-in method references. */
	var funcProto = Function.prototype,
	    objectProto = Object.prototype;

	/** Used to resolve the decompiled source of functions. */
	var funcToString = funcProto.toString;

	/** Used to check objects for own properties. */
	var hasOwnProperty = objectProto.hasOwnProperty;

	/** Used to infer the `Object` constructor. */
	var objectCtorString = funcToString.call(Object);

	/**
	 * Used to resolve the
	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
	 * of values.
	 */
	var objectToString = objectProto.toString;

	/** Built-in value references. */
	var getPrototype = overArg(Object.getPrototypeOf, Object);

	/**
	 * Checks if `value` is object-like. A value is object-like if it's not `null`
	 * and has a `typeof` result of "object".
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
	 * @example
	 *
	 * _.isObjectLike({});
	 * // => true
	 *
	 * _.isObjectLike([1, 2, 3]);
	 * // => true
	 *
	 * _.isObjectLike(_.noop);
	 * // => false
	 *
	 * _.isObjectLike(null);
	 * // => false
	 */
	function isObjectLike(value) {
	  return !!value && typeof value == 'object';
	}

	/**
	 * Checks if `value` is a plain object, that is, an object created by the
	 * `Object` constructor or one with a `[[Prototype]]` of `null`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.8.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
	 * @example
	 *
	 * function Foo() {
	 *   this.a = 1;
	 * }
	 *
	 * _.isPlainObject(new Foo);
	 * // => false
	 *
	 * _.isPlainObject([1, 2, 3]);
	 * // => false
	 *
	 * _.isPlainObject({ 'x': 0, 'y': 0 });
	 * // => true
	 *
	 * _.isPlainObject(Object.create(null));
	 * // => true
	 */
	function isPlainObject(value) {
	  if (!isObjectLike(value) ||
	      objectToString.call(value) != objectTag || isHostObject(value)) {
	    return false;
	  }
	  var proto = getPrototype(value);
	  if (proto === null) {
	    return true;
	  }
	  var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
	  return (typeof Ctor == 'function' &&
	    Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
	}

	module.exports = isPlainObject;


/***/ },
/* 26 */
/***/ function(module, exports) {

	/* WEBPACK VAR INJECTION */(function(global) {/**
	 * lodash (Custom Build) <https://lodash.com/>
	 * Build: `lodash modularize exports="npm" -o ./`
	 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
	 * Released under MIT license <https://lodash.com/license>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 */

	/** Used as the `TypeError` message for "Functions" methods. */
	var FUNC_ERROR_TEXT = 'Expected a function';

	/** Used as references for various `Number` constants. */
	var NAN = 0 / 0;

	/** `Object#toString` result references. */
	var symbolTag = '[object Symbol]';

	/** Used to match leading and trailing whitespace. */
	var reTrim = /^\s+|\s+$/g;

	/** Used to detect bad signed hexadecimal string values. */
	var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

	/** Used to detect binary string values. */
	var reIsBinary = /^0b[01]+$/i;

	/** Used to detect octal string values. */
	var reIsOctal = /^0o[0-7]+$/i;

	/** Built-in method references without a dependency on `root`. */
	var freeParseInt = parseInt;

	/** Detect free variable `global` from Node.js. */
	var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;

	/** Detect free variable `self`. */
	var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

	/** Used as a reference to the global object. */
	var root = freeGlobal || freeSelf || Function('return this')();

	/** Used for built-in method references. */
	var objectProto = Object.prototype;

	/**
	 * Used to resolve the
	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
	 * of values.
	 */
	var objectToString = objectProto.toString;

	/* Built-in method references for those with the same name as other `lodash` methods. */
	var nativeMax = Math.max,
	    nativeMin = Math.min;

	/**
	 * Gets the timestamp of the number of milliseconds that have elapsed since
	 * the Unix epoch (1 January 1970 00:00:00 UTC).
	 *
	 * @static
	 * @memberOf _
	 * @since 2.4.0
	 * @category Date
	 * @returns {number} Returns the timestamp.
	 * @example
	 *
	 * _.defer(function(stamp) {
	 *   console.log(_.now() - stamp);
	 * }, _.now());
	 * // => Logs the number of milliseconds it took for the deferred invocation.
	 */
	var now = function() {
	  return root.Date.now();
	};

	/**
	 * Creates a debounced function that delays invoking `func` until after `wait`
	 * milliseconds have elapsed since the last time the debounced function was
	 * invoked. The debounced function comes with a `cancel` method to cancel
	 * delayed `func` invocations and a `flush` method to immediately invoke them.
	 * Provide `options` to indicate whether `func` should be invoked on the
	 * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
	 * with the last arguments provided to the debounced function. Subsequent
	 * calls to the debounced function return the result of the last `func`
	 * invocation.
	 *
	 * **Note:** If `leading` and `trailing` options are `true`, `func` is
	 * invoked on the trailing edge of the timeout only if the debounced function
	 * is invoked more than once during the `wait` timeout.
	 *
	 * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
	 * until to the next tick, similar to `setTimeout` with a timeout of `0`.
	 *
	 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
	 * for details over the differences between `_.debounce` and `_.throttle`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Function
	 * @param {Function} func The function to debounce.
	 * @param {number} [wait=0] The number of milliseconds to delay.
	 * @param {Object} [options={}] The options object.
	 * @param {boolean} [options.leading=false]
	 *  Specify invoking on the leading edge of the timeout.
	 * @param {number} [options.maxWait]
	 *  The maximum time `func` is allowed to be delayed before it's invoked.
	 * @param {boolean} [options.trailing=true]
	 *  Specify invoking on the trailing edge of the timeout.
	 * @returns {Function} Returns the new debounced function.
	 * @example
	 *
	 * // Avoid costly calculations while the window size is in flux.
	 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
	 *
	 * // Invoke `sendMail` when clicked, debouncing subsequent calls.
	 * jQuery(element).on('click', _.debounce(sendMail, 300, {
	 *   'leading': true,
	 *   'trailing': false
	 * }));
	 *
	 * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
	 * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
	 * var source = new EventSource('/stream');
	 * jQuery(source).on('message', debounced);
	 *
	 * // Cancel the trailing debounced invocation.
	 * jQuery(window).on('popstate', debounced.cancel);
	 */
	function debounce(func, wait, options) {
	  var lastArgs,
	      lastThis,
	      maxWait,
	      result,
	      timerId,
	      lastCallTime,
	      lastInvokeTime = 0,
	      leading = false,
	      maxing = false,
	      trailing = true;

	  if (typeof func != 'function') {
	    throw new TypeError(FUNC_ERROR_TEXT);
	  }
	  wait = toNumber(wait) || 0;
	  if (isObject(options)) {
	    leading = !!options.leading;
	    maxing = 'maxWait' in options;
	    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
	    trailing = 'trailing' in options ? !!options.trailing : trailing;
	  }

	  function invokeFunc(time) {
	    var args = lastArgs,
	        thisArg = lastThis;

	    lastArgs = lastThis = undefined;
	    lastInvokeTime = time;
	    result = func.apply(thisArg, args);
	    return result;
	  }

	  function leadingEdge(time) {
	    // Reset any `maxWait` timer.
	    lastInvokeTime = time;
	    // Start the timer for the trailing edge.
	    timerId = setTimeout(timerExpired, wait);
	    // Invoke the leading edge.
	    return leading ? invokeFunc(time) : result;
	  }

	  function remainingWait(time) {
	    var timeSinceLastCall = time - lastCallTime,
	        timeSinceLastInvoke = time - lastInvokeTime,
	        result = wait - timeSinceLastCall;

	    return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
	  }

	  function shouldInvoke(time) {
	    var timeSinceLastCall = time - lastCallTime,
	        timeSinceLastInvoke = time - lastInvokeTime;

	    // Either this is the first call, activity has stopped and we're at the
	    // trailing edge, the system time has gone backwards and we're treating
	    // it as the trailing edge, or we've hit the `maxWait` limit.
	    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
	      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
	  }

	  function timerExpired() {
	    var time = now();
	    if (shouldInvoke(time)) {
	      return trailingEdge(time);
	    }
	    // Restart the timer.
	    timerId = setTimeout(timerExpired, remainingWait(time));
	  }

	  function trailingEdge(time) {
	    timerId = undefined;

	    // Only invoke if we have `lastArgs` which means `func` has been
	    // debounced at least once.
	    if (trailing && lastArgs) {
	      return invokeFunc(time);
	    }
	    lastArgs = lastThis = undefined;
	    return result;
	  }

	  function cancel() {
	    if (timerId !== undefined) {
	      clearTimeout(timerId);
	    }
	    lastInvokeTime = 0;
	    lastArgs = lastCallTime = lastThis = timerId = undefined;
	  }

	  function flush() {
	    return timerId === undefined ? result : trailingEdge(now());
	  }

	  function debounced() {
	    var time = now(),
	        isInvoking = shouldInvoke(time);

	    lastArgs = arguments;
	    lastThis = this;
	    lastCallTime = time;

	    if (isInvoking) {
	      if (timerId === undefined) {
	        return leadingEdge(lastCallTime);
	      }
	      if (maxing) {
	        // Handle invocations in a tight loop.
	        timerId = setTimeout(timerExpired, wait);
	        return invokeFunc(lastCallTime);
	      }
	    }
	    if (timerId === undefined) {
	      timerId = setTimeout(timerExpired, wait);
	    }
	    return result;
	  }
	  debounced.cancel = cancel;
	  debounced.flush = flush;
	  return debounced;
	}

	/**
	 * Checks if `value` is the
	 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
	 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
	 * @example
	 *
	 * _.isObject({});
	 * // => true
	 *
	 * _.isObject([1, 2, 3]);
	 * // => true
	 *
	 * _.isObject(_.noop);
	 * // => true
	 *
	 * _.isObject(null);
	 * // => false
	 */
	function isObject(value) {
	  var type = typeof value;
	  return !!value && (type == 'object' || type == 'function');
	}

	/**
	 * Checks if `value` is object-like. A value is object-like if it's not `null`
	 * and has a `typeof` result of "object".
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
	 * @example
	 *
	 * _.isObjectLike({});
	 * // => true
	 *
	 * _.isObjectLike([1, 2, 3]);
	 * // => true
	 *
	 * _.isObjectLike(_.noop);
	 * // => false
	 *
	 * _.isObjectLike(null);
	 * // => false
	 */
	function isObjectLike(value) {
	  return !!value && typeof value == 'object';
	}

	/**
	 * Checks if `value` is classified as a `Symbol` primitive or object.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
	 * @example
	 *
	 * _.isSymbol(Symbol.iterator);
	 * // => true
	 *
	 * _.isSymbol('abc');
	 * // => false
	 */
	function isSymbol(value) {
	  return typeof value == 'symbol' ||
	    (isObjectLike(value) && objectToString.call(value) == symbolTag);
	}

	/**
	 * Converts `value` to a number.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to process.
	 * @returns {number} Returns the number.
	 * @example
	 *
	 * _.toNumber(3.2);
	 * // => 3.2
	 *
	 * _.toNumber(Number.MIN_VALUE);
	 * // => 5e-324
	 *
	 * _.toNumber(Infinity);
	 * // => Infinity
	 *
	 * _.toNumber('3.2');
	 * // => 3.2
	 */
	function toNumber(value) {
	  if (typeof value == 'number') {
	    return value;
	  }
	  if (isSymbol(value)) {
	    return NAN;
	  }
	  if (isObject(value)) {
	    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
	    value = isObject(other) ? (other + '') : other;
	  }
	  if (typeof value != 'string') {
	    return value === 0 ? value : +value;
	  }
	  value = value.replace(reTrim, '');
	  var isBinary = reIsBinary.test(value);
	  return (isBinary || reIsOctal.test(value))
	    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
	    : (reIsBadHex.test(value) ? NAN : +value);
	}

	module.exports = debounce;

	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))

/***/ },
/* 27 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});

	var _tinycolor = __webpack_require__(28);

	var _tinycolor2 = _interopRequireDefault(_tinycolor);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	exports.default = {

	  simpleCheckForValidColor: function simpleCheckForValidColor(data) {
	    var keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'a', 'v'];
	    var checked = 0;
	    var passed = 0;
	    for (var i = 0; i < keysToCheck.length; i++) {
	      var letter = keysToCheck[i];
	      if (data[letter]) {
	        checked++;
	        if (!isNaN(data[letter])) {
	          passed++;
	        }
	      }
	    }

	    if (checked === passed) {
	      return data;
	    }
	  },

	  toState: function toState(data, oldHue) {
	    var color = data.hex ? (0, _tinycolor2.default)(data.hex) : (0, _tinycolor2.default)(data);
	    var hsl = color.toHsl();
	    var hsv = color.toHsv();
	    if (hsl.s === 0) {
	      hsl.h = oldHue || 0;
	      hsv.h = oldHue || 0;
	    }

	    return {
	      hsl: hsl,
	      hex: '#' + color.toHex(),
	      rgb: color.toRgb(),
	      hsv: hsv,
	      oldHue: data.h || oldHue || hsl.h,
	      source: data.source
	    };
	  },

	  isValidHex: function isValidHex(hex) {
	    return (0, _tinycolor2.default)(hex).isValid();
	  }

	};

/***/ },
/* 28 */
/***/ function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_RESULT__;// jscs: disable

	// TinyColor v1.1.2
	// https://github.com/bgrins/TinyColor
	// Brian Grinstead, MIT License

	(function() {

	var trimLeft = /^[\s,#]+/;
	var trimRight = /\s+$/;
	var tinyCounter = 0;
	var math = Math;
	var mathRound = math.round;
	var mathMin = math.min;
	var mathMax = math.max;
	var mathRandom = math.random;

	function tinycolor(color, opts) {

			color = (color) ? color : '';
			opts = opts || { };

			// If input is already a tinycolor, return itself
			if (color instanceof tinycolor) {
				 return color;
			}
			// If we are called as a function, call using new instead
			if (!(this instanceof tinycolor)) {
					return new tinycolor(color, opts);
			}

			var rgb = inputToRGB(color);
			this._originalInput = color,
			this._r = rgb.r,
			this._g = rgb.g,
			this._b = rgb.b,
			this._a = rgb.a,
			this._roundA = mathRound(100*this._a) / 100,
			this._format = opts.format || rgb.format;
			this._gradientType = opts.gradientType;

			// 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 by `inputToRgb`
			if (this._r < 1) { this._r = mathRound(this._r); }
			if (this._g < 1) { this._g = mathRound(this._g); }
			if (this._b < 1) { this._b = mathRound(this._b); }

			this._ok = rgb.ok;
			this._tc_id = tinyCounter++;
	}

	tinycolor.prototype = {
			isDark: function() {
					return this.getBrightness() < 128;
			},
			isLight: function() {
					return !this.isDark();
			},
			isValid: function() {
					return this._ok;
			},
			getOriginalInput: function() {
				return this._originalInput;
			},
			getFormat: function() {
					return this._format;
			},
			getAlpha: function() {
					return this._a;
			},
			getBrightness: function() {
					//http://www.w3.org/TR/AERT#color-contrast
					var rgb = this.toRgb();
					return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
			},
			getLuminance: function() {
					//http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
					var rgb = this.toRgb();
					var RsRGB, GsRGB, BsRGB, R, G, B;
					RsRGB = rgb.r/255;
					GsRGB = rgb.g/255;
					BsRGB = rgb.b/255;

					if (RsRGB <= 0.03928) {R = RsRGB / 12.92;} else {R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4);}
					if (GsRGB <= 0.03928) {G = GsRGB / 12.92;} else {G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4);}
					if (BsRGB <= 0.03928) {B = BsRGB / 12.92;} else {B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4);}
					return (0.2126 * R) + (0.7152 * G) + (0.0722 * B);
			},
			setAlpha: function(value) {
					this._a = boundAlpha(value);
					this._roundA = mathRound(100*this._a) / 100;
					return this;
			},
			toHsv: function() {
					var hsv = rgbToHsv(this._r, this._g, this._b);
					return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
			},
			toHsvString: function() {
					var hsv = rgbToHsv(this._r, this._g, this._b);
					var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
					return (this._a == 1) ?
						"hsv("	+ h + ", " + s + "%, " + v + "%)" :
						"hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
			},
			toHsl: function() {
					var hsl = rgbToHsl(this._r, this._g, this._b);
					return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
			},
			toHslString: function() {
					var hsl = rgbToHsl(this._r, this._g, this._b);
					var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
					return (this._a == 1) ?
						"hsl("	+ h + ", " + s + "%, " + l + "%)" :
						"hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
			},
			toHex: function(allow3Char) {
					return rgbToHex(this._r, this._g, this._b, allow3Char);
			},
			toHexString: function(allow3Char) {
					return '#' + this.toHex(allow3Char);
			},
			toHex8: function() {
					return rgbaToHex(this._r, this._g, this._b, this._a);
			},
			toHex8String: function() {
					return '#' + this.toHex8();
			},
			toRgb: function() {
					return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
			},
			toRgbString: function() {
					return (this._a == 1) ?
						"rgb("	+ mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
						"rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
			},
			toPercentageRgb: function() {
					return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
			},
			toPercentageRgbString: function() {
					return (this._a == 1) ?
						"rgb("	+ mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
						"rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
			},
			toName: function() {
					if (this._a === 0) {
							return "transparent";
					}

					if (this._a < 1) {
							return false;
					}

					return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
			},
			toFilter: function(secondColor) {
					var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
					var secondHex8String = hex8String;
					var gradientType = this._gradientType ? "GradientType = 1, " : "";

					if (secondColor) {
							var s = tinycolor(secondColor);
							secondHex8String = s.toHex8String();
					}

					return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
			},
			toString: function(format) {
					var formatSet = !!format;
					format = format || this._format;

					var formattedString = false;
					var hasAlpha = this._a < 1 && this._a >= 0;
					var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");

					if (needsAlphaFormat) {
							// Special case for "transparent", all other non-alpha formats
							// will return rgba when there is transparency.
							if (format === "name" && this._a === 0) {
									return this.toName();
							}
							return this.toRgbString();
					}
					if (format === "rgb") {
							formattedString = this.toRgbString();
					}
					if (format === "prgb") {
							formattedString = this.toPercentageRgbString();
					}
					if (format === "hex" || format === "hex6") {
							formattedString = this.toHexString();
					}
					if (format === "hex3") {
							formattedString = this.toHexString(true);
					}
					if (format === "hex8") {
							formattedString = this.toHex8String();
					}
					if (format === "name") {
							formattedString = this.toName();
					}
					if (format === "hsl") {
							formattedString = this.toHslString();
					}
					if (format === "hsv") {
							formattedString = this.toHsvString();
					}

					return formattedString || this.toHexString();
			},

			_applyModification: function(fn, args) {
					var color = fn.apply(null, [this].concat([].slice.call(args)));
					this._r = color._r;
					this._g = color._g;
					this._b = color._b;
					this.setAlpha(color._a);
					return this;
			},
			lighten: function() {
					return this._applyModification(lighten, arguments);
			},
			brighten: function() {
					return this._applyModification(brighten, arguments);
			},
			darken: function() {
					return this._applyModification(darken, arguments);
			},
			desaturate: function() {
					return this._applyModification(desaturate, arguments);
			},
			saturate: function() {
					return this._applyModification(saturate, arguments);
			},
			greyscale: function() {
					return this._applyModification(greyscale, arguments);
			},
			spin: function() {
					return this._applyModification(spin, arguments);
			},

			_applyCombination: function(fn, args) {
					return fn.apply(null, [this].concat([].slice.call(args)));
			},
			analogous: function() {
					return this._applyCombination(analogous, arguments);
			},
			complement: function() {
					return this._applyCombination(complement, arguments);
			},
			monochromatic: function() {
					return this._applyCombination(monochromatic, arguments);
			},
			splitcomplement: function() {
					return this._applyCombination(splitcomplement, arguments);
			},
			triad: function() {
					return this._applyCombination(triad, arguments);
			},
			tetrad: function() {
					return this._applyCombination(tetrad, arguments);
			}
	};

	// 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, opts) {
			if (typeof color == "object") {
					var newColor = {};
					for (var i in color) {
							if (color.hasOwnProperty(i)) {
									if (i === "a") {
											newColor[i] = color[i];
									}
									else {
											newColor[i] = convertToPercentage(color[i]);
									}
							}
					}
					color = newColor;
			}

			return tinycolor(color, opts);
	};

	// Given a string or object, convert that input to RGB
	// Possible string inputs:
	//
	//		 "red"
	//		 "#f00" or "f00"
	//		 "#ff0000" or "ff0000"
	//		 "#ff000000" or "ff000000"
	//		 "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 = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
					}
					else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
							color.s = convertToPercentage(color.s, 1);
							color.v = convertToPercentage(color.v, 1);
							rgb = hsvToRgb(color.h, color.s, color.v);
							ok = true;
							format = "hsv";
					}
					else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
							color.s = convertToPercentage(color.s);
							color.l = convertToPercentage(color.l);
							rgb = hslToRgb(color.h, color.s, color.l);
							ok = true;
							format = "hsl";
					}

					if (color.hasOwnProperty("a")) {
							a = color.a;
					}
			}

			a = boundAlpha(a);

			return {
					ok: ok,
					format: color.format || format,
					r: mathMin(255, mathMax(rgb.r, 0)),
					g: mathMin(255, mathMax(rgb.g, 0)),
					b: mathMin(255, mathMax(rgb.b, 0)),
					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) {

			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, allow3Char) {

			var hex = [
					pad2(mathRound(r).toString(16)),
					pad2(mathRound(g).toString(16)),
					pad2(mathRound(b).toString(16))
			];

			// Return a 3 character hex if possible
			if (allow3Char && 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("");
	}
			// `rgbaToHex`
			// Converts an RGBA color plus alpha transparency to hex
			// Assumes r, g, b and a are contained in the set [0, 255]
			// Returns an 8 character hex
			function rgbaToHex(r, g, b, a) {

					var hex = [
							pad2(convertDecimalToHex(a)),
							pad2(mathRound(r).toString(16)),
							pad2(mathRound(g).toString(16)),
							pad2(mathRound(b).toString(16))
					];

					return hex.join("");
			}

	// `equals`
	// Can be called with any tinycolor input
	tinycolor.equals = function (color1, color2) {
			if (!color1 || !color2) { return false; }
			return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
	};
	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>

	function desaturate(color, amount) {
			amount = (amount === 0) ? 0 : (amount || 10);
			var hsl = tinycolor(color).toHsl();
			hsl.s -= amount / 100;
			hsl.s = clamp01(hsl.s);
			return tinycolor(hsl);
	}

	function saturate(color, amount) {
			amount = (amount === 0) ? 0 : (amount || 10);
			var hsl = tinycolor(color).toHsl();
			hsl.s += amount / 100;
			hsl.s = clamp01(hsl.s);
			return tinycolor(hsl);
	}

	function greyscale(color) {
			return tinycolor(color).desaturate(100);
	}

	function lighten (color, amount) {
			amount = (amount === 0) ? 0 : (amount || 10);
			var hsl = tinycolor(color).toHsl();
			hsl.l += amount / 100;
			hsl.l = clamp01(hsl.l);
			return tinycolor(hsl);
	}

	function brighten(color, amount) {
			amount = (amount === 0) ? 0 : (amount || 10);
			var rgb = tinycolor(color).toRgb();
			rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
			rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
			rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
			return tinycolor(rgb);
	}

	function darken (color, amount) {
			amount = (amount === 0) ? 0 : (amount || 10);
			var hsl = tinycolor(color).toHsl();
			hsl.l -= amount / 100;
			hsl.l = clamp01(hsl.l);
			return tinycolor(hsl);
	}

	// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
	// Values outside of this range will be wrapped into this range.
	function spin(color, amount) {
			var hsl = tinycolor(color).toHsl();
			var hue = (mathRound(hsl.h) + amount) % 360;
			hsl.h = hue < 0 ? 360 + hue : hue;
			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>

	function complement(color) {
			var hsl = tinycolor(color).toHsl();
			hsl.h = (hsl.h + 180) % 360;
			return tinycolor(hsl);
	}

	function triad(color) {
			var hsl = tinycolor(color).toHsl();
			var h = hsl.h;
			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 })
			];
	}

	function tetrad(color) {
			var hsl = tinycolor(color).toHsl();
			var h = hsl.h;
			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 })
			];
	}

	function splitcomplement(color) {
			var hsl = tinycolor(color).toHsl();
			var h = hsl.h;
			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})
			];
	}

	function analogous(color, results, slices) {
			results = results || 6;
			slices = slices || 30;

			var hsl = tinycolor(color).toHsl();
			var part = 360 / slices;
			var ret = [tinycolor(color)];

			for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
					hsl.h = (hsl.h + part) % 360;
					ret.push(tinycolor(hsl));
			}
			return ret;
	}

	function monochromatic(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;
	}

	// Utility Functions
	// ---------------------

	tinycolor.mix = function(color1, color2, amount) {
			amount = (amount === 0) ? 0 : (amount || 50);

			var rgb1 = tinycolor(color1).toRgb();
			var rgb2 = tinycolor(color2).toRgb();

			var p = amount / 100;
			var w = p * 2 - 1;
			var a = rgb2.a - rgb1.a;

			var w1;

			if (w * a == -1) {
					w1 = w;
			} else {
					w1 = (w + a) / (1 + w * a);
			}

			w1 = (w1 + 1) / 2;

			var w2 = 1 - w1;

			var rgba = {
					r: rgb2.r * w1 + rgb1.r * w2,
					g: rgb2.g * w1 + rgb1.g * w2,
					b: rgb2.b * w1 + rgb1.b * w2,
					a: rgb2.a * p	+ rgb1.a * (1 - p)
			};

			return tinycolor(rgba);
	};


	// Readability Functions
	// ---------------------
	// <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)

	// `contrast`
	// Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2)
	tinycolor.readability = function(color1, color2) {
			var c1 = tinycolor(color1);
			var c2 = tinycolor(color2);
			return (Math.max(c1.getLuminance(),c2.getLuminance())+0.05) / (Math.min(c1.getLuminance(),c2.getLuminance())+0.05);
	};

	// `isReadable`
	// Ensure that foreground and background color combinations meet WCAG2 guidelines.
	// The third argument is an optional Object.
	//			the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA';
	//			the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'.
	// If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}.

	// *Example*
	//		tinycolor.isReadable("#000", "#111") => false
	//		tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false

	tinycolor.isReadable = function(color1, color2, wcag2) {
			var readability = tinycolor.readability(color1, color2);
			var wcag2Parms, out;

			out = false;

			wcag2Parms = validateWCAG2Parms(wcag2);
			switch (wcag2Parms.level + wcag2Parms.size) {
					case "AAsmall":
					case "AAAlarge":
							out = readability >= 4.5;
							break;
					case "AAlarge":
							out = readability >= 3;
							break;
					case "AAAsmall":
							out = readability >= 7;
							break;
			}
			return out;

	};

	// `mostReadable`
	// Given a base color and a list of possible foreground or background
	// colors for that base, returns the most readable color.
	// Optionally returns Black or White if the most readable color is unreadable.
	// *Example*
	//		tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255"
	//		tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString();	// "#ffffff"
	//		tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3"
	//		tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff"


	tinycolor.mostReadable = function(baseColor, colorList, args) {
			var bestColor = null;
			var bestScore = 0;
			var readability;
			var includeFallbackColors, level, size ;
			args = args || {};
			includeFallbackColors = args.includeFallbackColors ;
			level = args.level;
			size = args.size;

			for (var i= 0; i < colorList.length ; i++) {
					readability = tinycolor.readability(baseColor, colorList[i]);
					if (readability > bestScore) {
							bestScore = readability;
							bestColor = tinycolor(colorList[i]);
					}
			}

			if (tinycolor.isReadable(baseColor, bestColor, {"level":level,"size":size}) || !includeFallbackColors) {
					return bestColor;
			}
			else {
					args.includeFallbackColors=false;
					return tinycolor.mostReadable(baseColor,["#fff", "#000"],args);
			}
	};


	// 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",
			rebeccapurple: "663399",
			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;
	}

	// Return a valid alpha value [0,1] with all invalid values being set to 1
	function boundAlpha(a) {
			a = parseFloat(a);

			if (isNaN(a) || a < 0 || a > 1) {
					a = 1;
			}

			return a;
	}

	// 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 = parseInt(n * max, 10) / 100;
			}

			// Handle floating point rounding errors
			if ((math.abs(n - max) < 0.000001)) {
					return 1;
			}

			// Convert into [0, 1] range if it isn't already
			return (n % max) / parseFloat(max);
	}

	// Force a number between 0 and 1
	function clamp01(val) {
			return mathMin(1, mathMax(0, val));
	}

	// Parse a base-16 hex value into a base-10 integer
	function parseIntFromHex(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;
	}

	// Force a hex value to have 2 characters
	function pad2(c) {
			return c.length == 1 ? '0' + c : '' + c;
	}

	// Replace a decimal with it's percentage value
	function convertToPercentage(n, multiplier) {
			multiplier = multiplier || 100;
			if (n <= 1) {
					n = (n * multiplier) + "%";
			}

			return n;
	}

	// Converts a decimal to a hex value
	function convertDecimalToHex(d) {
			return Math.round(parseFloat(d) * 255).toString(16);
	}
	// Converts a hex value to a decimal
	function convertHexToDecimal(h) {
			return (parseIntFromHex(h) / 255);
	}

	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),
					hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
					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})$/,
					hex8: /^([0-9a-fA-F]{2})([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, format: "name" };
			}

			// 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.hsva.exec(color))) {
					return { h: match[1], s: match[2], v: match[3], a: match[4] };
			}
			if ((match = matchers.hex8.exec(color))) {
					return {
							a: convertHexToDecimal(match[1]),
							r: parseIntFromHex(match[2]),
							g: parseIntFromHex(match[3]),
							b: parseIntFromHex(match[4]),
							format: named ? "name" : "hex8"
					};
			}
			if ((match = matchers.hex6.exec(color))) {
					return {
							r: parseIntFromHex(match[1]),
							g: parseIntFromHex(match[2]),
							b: parseIntFromHex(match[3]),
							format: named ? "name" : "hex"
					};
			}
			if ((match = matchers.hex3.exec(color))) {
					return {
							r: parseIntFromHex(match[1] + '' + match[1]),
							g: parseIntFromHex(match[2] + '' + match[2]),
							b: parseIntFromHex(match[3] + '' + match[3]),
							format: named ? "name" : "hex"
					};
			}

			return false;
	}

	function validateWCAG2Parms(parms) {
			// return valid WCAG2 parms for isReadable.
			// If input parms are invalid, return {"level":"AA", "size":"small"}
			var level, size;
			parms = parms || {"level":"AA", "size":"small"};
			level = (parms.level || "AA").toUpperCase();
			size = (parms.size || "small").toLowerCase();
			if (level !== "AA" && level !== "AAA") {
					level = "AA";
			}
			if (size !== "small" && size !== "large") {
					size = "small";
			}
			return {"level":level, "size":size};
	}
	// Node: Export function
	if (typeof module !== "undefined" && module.exports) {
			module.exports = tinycolor;
	}
	// AMD/requirejs: Define the module
	else if (true) {
			!(__WEBPACK_AMD_DEFINE_RESULT__ = function () {return tinycolor;}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	}
	// Browser: Expose to window
	else {
			window.tinycolor = tinycolor;
	}

	})();


/***/ },
/* 29 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.ChromePointer = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var ChromePointer = exports.ChromePointer = function (_ReactCSS$Component) {
	  _inherits(ChromePointer, _ReactCSS$Component);

	  function ChromePointer() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, ChromePointer);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ChromePointer.__proto__ || Object.getPrototypeOf(ChromePointer)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(ChromePointer, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          picker: {
	            width: '10px',
	            height: '16px',
	            borderRadius: '5px',
	            transform: 'translate(-5px, 0px)',
	            backgroundColor: 'rgb(248, 248, 248)',
	            boxShadow: '0 1px 4px 0 rgba(0, 0, 0, 0.37)'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      return _react2.default.createElement('div', { style: this.styles().picker });
	    }
	  }]);

	  return ChromePointer;
	}(_reactcss2.default.Component);

	exports.default = ChromePointer;

/***/ },
/* 30 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.ChromePointerCircle = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var ChromePointerCircle = exports.ChromePointerCircle = function (_ReactCSS$Component) {
	  _inherits(ChromePointerCircle, _ReactCSS$Component);

	  function ChromePointerCircle() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, ChromePointerCircle);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ChromePointerCircle.__proto__ || Object.getPrototypeOf(ChromePointerCircle)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(ChromePointerCircle, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          picker: {
	            width: '12px',
	            height: '12px',
	            borderRadius: '6px',
	            boxShadow: 'inset 0 0 0 1px #fff',
	            transform: 'translate(-6px, -6px)'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      return _react2.default.createElement('div', { style: this.styles().picker });
	    }
	  }]);

	  return ChromePointerCircle;
	}(_reactcss2.default.Component);

	exports.default = ChromePointerCircle;

/***/ },
/* 31 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.CompactColor = undefined;

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _react = __webpack_require__(3);

	var _react2 = _interopRequireDefault(_react);

	var _reactcss = __webpack_require__(4);

	var _reactcss2 = _interopRequireDefault(_reactcss);

	var _reactAddonsShallowCompare = __webpack_require__(17);

	var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

	var CompactColor = exports.CompactColor = function (_ReactCSS$Component) {
	  _inherits(CompactColor, _ReactCSS$Component);

	  function CompactColor() {
	    var _ref;

	    var _temp, _this, _ret;

	    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    _classCallCheck(this, CompactColor);

	    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = CompactColor.__proto__ || Object.getPrototypeOf(CompactColor)).call.apply(_ref, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _this.handleClick = function () {
	      _this.props.onClick({ hex: _this.props.color });
	    }, _temp), _possibleConstructorReturn(_this, _ret);
	  }

	  _createClass(CompactColor, [{
	    key: 'classes',
	    value: function classes() {
	      return {
	        'default': {
	          color: {
	            background: this.props.color,
	            //width: '15px',
	            height: '15px',
	            // float: 'left',
	            //margin: '4px 2px',
	            //marginBottom: '5px',
	            //position: 'relative',
	            cursor: 'pointer',
	            flexGrow: '1'
	          }
	        }
	      };
	    }
	  }, {
	    key: 'render',
	    value: function render() {
	      return _react2.default.createElement('div', { style: this.styles().color, ref: 'color', onClick: this.handleClick });
	    }
	  }]);

	  return CompactColor;
	}(_reactcss2.default.Component);

	exports.default = CompactColor;

/***/ }
/******/ ]);
"use strict";
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    //export type Promise<T> = GlobalPromise<T>;// __Promise.Promise<T>;
    LiteMol.Promise = __LiteMolPromise;
})(LiteMol || (LiteMol = {}));
(function (LiteMol) {
    var Core;
    (function (Core) {
        "use strict";
        Core.Rx = __LiteMolRx;
        Core.Promise = LiteMol.Promise;
        var Formats;
        (function (Formats) {
            Formats.CIF = LiteMolCIFTools;
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        Core.VERSION = { number: "3.2.2", date: "Nov 14 2017" };
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Scheduler;
        (function (Scheduler) {
            "use strict";
            function createImmediateActions() {
                var tasksByHandle = {};
                var doc = typeof document !== 'undefined' ? document : void 0;
                var currentlyRunningATask = false;
                var nextHandle = 1; // Spec says greater than zero
                var registerImmediate;
                function setImmediate(callback) {
                    var args = [];
                    for (var _i = 1; _i < arguments.length; _i++) {
                        args[_i - 1] = arguments[_i];
                    }
                    // Callback can either be a function or a string
                    if (typeof callback !== 'function') {
                        callback = new Function('' + callback);
                    }
                    // Store and register the task
                    var task = { callback: callback, args: args };
                    tasksByHandle[nextHandle] = task;
                    registerImmediate(nextHandle);
                    return nextHandle++;
                }
                function clearImmediate(handle) {
                    delete tasksByHandle[handle];
                }
                function run(task) {
                    var callback = task.callback;
                    var args = task.args;
                    switch (args.length) {
                        case 0:
                            callback();
                            break;
                        case 1:
                            callback(args[0]);
                            break;
                        case 2:
                            callback(args[0], args[1]);
                            break;
                        case 3:
                            callback(args[0], args[1], args[2]);
                            break;
                        default:
                            callback.apply(undefined, args);
                            break;
                    }
                }
                function runIfPresent(handle) {
                    // From the spec: 'Wait until any invocations of this algorithm started before this one have completed.'
                    // So if we're currently running a task, we'll need to delay this invocation.
                    if (currentlyRunningATask) {
                        // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
                        // 'too much recursion' error.
                        setTimeout(runIfPresent, 0, handle);
                    }
                    else {
                        var task = tasksByHandle[handle];
                        if (task) {
                            currentlyRunningATask = true;
                            try {
                                run(task);
                            }
                            finally {
                                clearImmediate(handle);
                                currentlyRunningATask = false;
                            }
                        }
                    }
                }
                function installNextTickImplementation() {
                    registerImmediate = function (handle) {
                        process.nextTick(function () { runIfPresent(handle); });
                    };
                }
                function canUsePostMessage() {
                    // The test against `importScripts` prevents this implementation from being installed inside a web worker,
                    // where `global.postMessage` means something completely different and can't be used for this purpose.
                    var global = window;
                    if (global && global.postMessage && !global.importScripts) {
                        var postMessageIsAsynchronous_1 = true;
                        var oldOnMessage = global.onmessage;
                        global.onmessage = function () {
                            postMessageIsAsynchronous_1 = false;
                        };
                        global.postMessage('', '*');
                        global.onmessage = oldOnMessage;
                        return postMessageIsAsynchronous_1;
                    }
                    return void 0;
                }
                function installPostMessageImplementation() {
                    // Installs an event handler on `global` for the `message` event: see
                    // * https://developer.mozilla.org/en/DOM/window.postMessage
                    // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
                    var global = window;
                    var messagePrefix = 'setImmediate$' + Math.random() + '$';
                    var onGlobalMessage = function (event) {
                        if (event.source === global &&
                            typeof event.data === 'string' &&
                            event.data.indexOf(messagePrefix) === 0) {
                            runIfPresent(+event.data.slice(messagePrefix.length));
                        }
                    };
                    if (window.addEventListener) {
                        window.addEventListener('message', onGlobalMessage, false);
                    }
                    else {
                        window.attachEvent('onmessage', onGlobalMessage);
                    }
                    registerImmediate = function (handle) {
                        window.postMessage(messagePrefix + handle, '*');
                    };
                }
                function installMessageChannelImplementation() {
                    var channel = new MessageChannel();
                    channel.port1.onmessage = function (event) {
                        var handle = event.data;
                        runIfPresent(handle);
                    };
                    registerImmediate = function (handle) {
                        channel.port2.postMessage(handle);
                    };
                }
                function installReadyStateChangeImplementation() {
                    var html = doc.documentElement;
                    registerImmediate = function (handle) {
                        // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
                        // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
                        var script = doc.createElement('script');
                        script.onreadystatechange = function () {
                            runIfPresent(handle);
                            script.onreadystatechange = null;
                            html.removeChild(script);
                            script = null;
                        };
                        html.appendChild(script);
                    };
                }
                function installSetTimeoutImplementation() {
                    registerImmediate = function (handle) {
                        setTimeout(runIfPresent, 0, handle);
                    };
                }
                // Don't get fooled by e.g. browserify environments.
                if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
                    // For Node.js before 0.9
                    installNextTickImplementation();
                }
                else if (canUsePostMessage()) {
                    // For non-IE10 modern browsers
                    installPostMessageImplementation();
                }
                else if (typeof MessageChannel !== 'undefined') {
                    // For web workers, where supported
                    installMessageChannelImplementation();
                }
                else if (doc && 'onreadystatechange' in doc.createElement('script')) {
                    // For IE 6–8
                    installReadyStateChangeImplementation();
                }
                else {
                    // For older browsers
                    installSetTimeoutImplementation();
                }
                return {
                    setImmediate: setImmediate,
                    clearImmediate: clearImmediate
                };
            }
            var immediateActions = (function () {
                if (typeof setImmediate !== 'undefined') {
                    if (typeof window !== 'undefined' && typeof window.setImmediate !== 'undefined') {
                        // this is because of IE
                        return { setImmediate: function (handler) {
                                var args = [];
                                for (var _i = 1; _i < arguments.length; _i++) {
                                    args[_i - 1] = arguments[_i];
                                }
                                return window.setImmediate.apply(window, [handler].concat(args));
                            }, clearImmediate: function (handle) { return window.clearImmediate(handle); } };
                    }
                    else
                        return { setImmediate: setImmediate, clearImmediate: Scheduler.clearImmediate };
                }
                return createImmediateActions();
            }());
            function resolveImmediate(res) {
                immediateActions.setImmediate(res);
            }
            Scheduler.immediate = immediateActions.setImmediate;
            Scheduler.clearImmediate = immediateActions.clearImmediate;
            function immediatePromise() { return new Core.Promise(resolveImmediate); }
            Scheduler.immediatePromise = immediatePromise;
        })(Scheduler = Core.Scheduler || (Core.Scheduler = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        "use strict";
        function computation(c) {
            return new Computation(c);
        }
        Core.computation = computation;
        var Computation = /** @class */ (function () {
            function Computation(computation) {
                this.computation = computation;
            }
            Computation.prototype.run = function (ctx) {
                return this.runWithContext(ctx).result;
            };
            Computation.prototype.runWithContext = function (ctx) {
                var _this = this;
                var context = ctx ? ctx : new ContextImpl();
                return {
                    progress: context.progressStream,
                    result: new Core.Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
                        var result, e_1;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    _a.trys.push([0, 2, 3, 4]);
                                    context.started();
                                    return [4 /*yield*/, this.computation(context)];
                                case 1:
                                    result = _a.sent();
                                    resolve(result);
                                    return [3 /*break*/, 4];
                                case 2:
                                    e_1 = _a.sent();
                                    if (Computation.PRINT_CONSOLE_ERROR)
                                        console.error(e_1);
                                    reject(e_1);
                                    return [3 /*break*/, 4];
                                case 3:
                                    context.finished();
                                    return [7 /*endfinally*/];
                                case 4: return [2 /*return*/];
                            }
                        });
                    }); })
                };
            };
            return Computation;
        }());
        Core.Computation = Computation;
        (function (Computation) {
            Computation.PRINT_CONSOLE_ERROR = false;
            function resolve(a) {
                return computation(function () { return Core.Promise.resolve(a); });
            }
            Computation.resolve = resolve;
            function reject(reason) {
                return computation(function () { return Core.Promise.reject(reason); });
            }
            Computation.reject = reject;
            function createContext() {
                return new ContextImpl();
            }
            Computation.createContext = createContext;
            Computation.Aborted = 'Aborted';
            Computation.UpdateProgressDelta = 100;
        })(Computation = Core.Computation || (Core.Computation = {}));
        var ContextImpl = /** @class */ (function () {
            function ContextImpl() {
                var _this = this;
                this._abortRequested = false;
                this._abortRequester = function () { _this._abortRequested = true; };
                this.progressTick = new Core.Rx.Subject();
                this._progress = { message: 'Working...', current: 0, max: 0, isIndeterminate: true, requestAbort: void 0 };
                this.progressStream = new Core.Rx.BehaviorSubject(this._progress);
                this.startEndCounter = 0;
                this.progressTick.throttle(1000 / 15).subscribe(function (p) {
                    _this.progressStream.onNext({
                        message: p.message,
                        isIndeterminate: p.isIndeterminate,
                        current: p.current,
                        max: p.max,
                        requestAbort: p.requestAbort
                    });
                });
            }
            Object.defineProperty(ContextImpl.prototype, "isAbortRequested", {
                get: function () {
                    return this._abortRequested;
                },
                enumerable: true,
                configurable: true
            });
            ContextImpl.prototype.checkAborted = function () {
                if (this._abortRequested)
                    throw Computation.Aborted;
            };
            ContextImpl.prototype.requestAbort = function () {
                try {
                    if (this._abortRequester) {
                        this._abortRequester.call(null);
                    }
                }
                catch (e) { }
            };
            Object.defineProperty(ContextImpl.prototype, "progress", {
                get: function () { return this.progressTick; },
                enumerable: true,
                configurable: true
            });
            ContextImpl.prototype.updateProgress = function (msg, abort, current, max) {
                if (current === void 0) { current = NaN; }
                if (max === void 0) { max = NaN; }
                this.checkAborted();
                this._progress.message = msg;
                if (typeof abort === 'boolean') {
                    this._progress.requestAbort = abort ? this._abortRequester : void 0;
                }
                else {
                    if (abort)
                        this._abortRequester = abort;
                    this._progress.requestAbort = abort ? this._abortRequester : void 0;
                }
                if (isNaN(current)) {
                    this._progress.isIndeterminate = true;
                }
                else {
                    this._progress.isIndeterminate = false;
                    this._progress.current = current;
                    this._progress.max = max;
                }
                this.progressTick.onNext(this._progress);
                return Core.Scheduler.immediatePromise();
                //return new Promise<void>(res => setTimeout(res, 0));
            };
            ContextImpl.prototype.started = function () {
                this.startEndCounter++;
            };
            ContextImpl.prototype.finished = function () {
                this.startEndCounter--;
                if (this.startEndCounter <= 0) {
                    this.progressTick.onCompleted();
                    this.progressStream.onCompleted();
                }
                if (this.startEndCounter < 0) {
                    throw 'Bug in code somewhere, Computation.resolve/reject called too many times.';
                }
            };
            return ContextImpl;
        }());
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Utils;
        (function (Utils) {
            "use strict";
            function createMapObject() {
                var map = Object.create(null);
                // to cause deoptimization as we don't want to create hidden classes
                map["__"] = void 0;
                delete map["__"];
                return map;
            }
            var FastMap;
            (function (FastMap) {
                function forEach(data, f, ctx) {
                    for (var _i = 0, _a = Object.keys(data); _i < _a.length; _i++) {
                        var key = _a[_i];
                        var v = data[key];
                        if (v === void 0)
                            continue;
                        f(v, key, ctx);
                    }
                }
                var fastMap = {
                    set: function (key, v) {
                        if (this.data[key] === void 0 && v !== void 0) {
                            this.size++;
                        }
                        this.data[key] = v;
                    },
                    get: function (key) {
                        return this.data[key];
                    },
                    delete: function (key) {
                        if (this.data[key] === void 0)
                            return false;
                        delete this.data[key];
                        this.size--;
                        return true;
                    },
                    has: function (key) {
                        return this.data[key] !== void 0;
                    },
                    clear: function () {
                        this.data = createMapObject();
                        this.size = 0;
                    },
                    forEach: function (f, ctx) {
                        forEach(this.data, f, ctx !== void 0 ? ctx : void 0);
                    }
                };
                /**
                 * Creates an empty map.
                 */
                function create() {
                    var ret = Object.create(fastMap);
                    ret.data = createMapObject();
                    ret.size = 0;
                    return ret;
                }
                FastMap.create = create;
                /**
                 * Create a map from an array of the form [[key, value], ...]
                 */
                function ofArray(data) {
                    var ret = create();
                    for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
                        var xs = data_1[_i];
                        ret.set(xs[0], xs[1]);
                    }
                    return ret;
                }
                FastMap.ofArray = ofArray;
                /**
                 * Create a map from an object of the form { key: value, ... }
                 */
                function ofObject(data) {
                    var ret = create();
                    for (var _i = 0, _a = Object.keys(data); _i < _a.length; _i++) {
                        var key = _a[_i];
                        var v = data[key];
                        ret.set(key, v);
                    }
                    return ret;
                }
                FastMap.ofObject = ofObject;
            })(FastMap = Utils.FastMap || (Utils.FastMap = {}));
            var FastSet;
            (function (FastSet) {
                function forEach(data, f, ctx) {
                    for (var _i = 0, _a = Object.keys(data); _i < _a.length; _i++) {
                        var p = _a[_i];
                        if (data[p] !== null)
                            continue;
                        f(p, ctx);
                    }
                }
                /**
                 * Uses null for present values.
                 */
                var fastSet = {
                    add: function (key) {
                        if (this.data[key] === null)
                            return false;
                        this.data[key] = null;
                        this.size++;
                        return true;
                    },
                    delete: function (key) {
                        if (this.data[key] !== null)
                            return false;
                        delete this.data[key];
                        this.size--;
                        return true;
                    },
                    has: function (key) {
                        return this.data[key] === null;
                    },
                    clear: function () {
                        this.data = createMapObject();
                        this.size = 0;
                    },
                    forEach: function (f, ctx) {
                        forEach(this.data, f, ctx !== void 0 ? ctx : void 0);
                    }
                };
                /**
                 * Create an empty set.
                 */
                function create() {
                    var ret = Object.create(fastSet);
                    ret.data = createMapObject();
                    ret.size = 0;
                    return ret;
                }
                FastSet.create = create;
                /**
                 * Create a set of an "array like" sequence.
                 */
                function ofArray(xs) {
                    var ret = create();
                    for (var i = 0, l = xs.length; i < l; i++) {
                        ret.add(xs[i]);
                    }
                    return ret;
                }
                FastSet.ofArray = ofArray;
            })(FastSet = Utils.FastSet || (Utils.FastSet = {}));
            var Mask;
            (function (Mask) {
                var EmptyMask = /** @class */ (function () {
                    function EmptyMask(size) {
                        this.size = size;
                    }
                    EmptyMask.prototype.has = function (i) { return false; };
                    return EmptyMask;
                }());
                var SingletonMask = /** @class */ (function () {
                    function SingletonMask(idx, size) {
                        this.idx = idx;
                        this.size = size;
                    }
                    SingletonMask.prototype.has = function (i) { return i === this.idx; };
                    return SingletonMask;
                }());
                var BitMask = /** @class */ (function () {
                    function BitMask(mask, size) {
                        this.mask = mask;
                        this.size = size;
                    }
                    BitMask.prototype.has = function (i) { return this.mask[i]; };
                    return BitMask;
                }());
                var AllMask = /** @class */ (function () {
                    function AllMask(size) {
                        this.size = size;
                    }
                    AllMask.prototype.has = function (i) { return true; };
                    return AllMask;
                }());
                function ofStructure(structure) {
                    return new AllMask(structure.data.atoms.count);
                }
                Mask.ofStructure = ofStructure;
                function ofIndices(totalCount, indices) {
                    var len = indices.length;
                    if (len === 0)
                        return new EmptyMask(totalCount);
                    if (len === 1)
                        return new SingletonMask(indices[0], totalCount);
                    var f = len / totalCount;
                    if (f < 1 / 12) {
                        var set = Utils.FastSet.create();
                        for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
                            var i = indices_1[_i];
                            set.add(i);
                        }
                        return set;
                    }
                    var mask = new Int8Array(totalCount);
                    for (var _a = 0, indices_2 = indices; _a < indices_2.length; _a++) {
                        var i = indices_2[_a];
                        mask[i] = 1;
                    }
                    return new BitMask(mask, len);
                }
                Mask.ofIndices = ofIndices;
                function ofFragments(seq) {
                    var sizeEstimate = 0;
                    for (var _i = 0, _a = seq.fragments; _i < _a.length; _i++) {
                        var f = _a[_i];
                        sizeEstimate += f.atomCount;
                    }
                    var count = seq.context.structure.data.atoms.count;
                    if (sizeEstimate / count < 1 / 12) {
                        // create set;
                        var mask = Utils.FastSet.create();
                        for (var _b = 0, _c = seq.fragments; _b < _c.length; _b++) {
                            var f = _c[_b];
                            for (var _d = 0, _e = f.atomIndices; _d < _e.length; _d++) {
                                var i = _e[_d];
                                mask.add(i);
                            }
                        }
                        return mask;
                    }
                    else {
                        var mask = new Int8Array(count);
                        for (var _f = 0, _g = seq.fragments; _f < _g.length; _f++) {
                            var f = _g[_f];
                            for (var _h = 0, _j = f.atomIndices; _h < _j.length; _h++) {
                                var i = _j[_h];
                                mask[i] = 1;
                            }
                        }
                        var size = 0;
                        for (var i = 0; i < count; i++) {
                            if (mask[i] !== 0)
                                size++;
                        }
                        return new BitMask(mask, size);
                    }
                }
                Mask.ofFragments = ofFragments;
            })(Mask = Utils.Mask || (Utils.Mask = {}));
        })(Utils = Core.Utils || (Core.Utils = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Utils;
        (function (Utils) {
            "use strict";
            Utils.FastNumberParsers = Core.Formats.CIF.Utils.FastNumberParsers;
            function extend(object, source, guard) {
                var v;
                var s = source;
                var o = object;
                var g = guard;
                for (var _i = 0, _a = Object.keys(source); _i < _a.length; _i++) {
                    var k = _a[_i];
                    v = s[k];
                    if (v !== void 0)
                        o[k] = v;
                    else if (guard)
                        o[k] = g[k];
                }
                if (guard) {
                    for (var _b = 0, _c = Object.keys(guard); _b < _c.length; _b++) {
                        var k = _c[_b];
                        v = o[k];
                        if (v === void 0)
                            o[k] = g[k];
                    }
                }
                return object;
            }
            Utils.extend = extend;
            ;
            function debounce(func, wait) {
                var args, maxTimeoutId, result, stamp, thisArg, timeoutId, trailingCall, lastCalled = 0, maxWait = 0, trailing = true, leading = false;
                wait = Math.max(0, wait) || 0;
                var delayed = function () {
                    var remaining = wait - (performance.now() - stamp);
                    if (remaining <= 0) {
                        if (maxTimeoutId) {
                            clearTimeout(maxTimeoutId);
                        }
                        var isCalled = trailingCall;
                        maxTimeoutId = timeoutId = trailingCall = void 0;
                        if (isCalled) {
                            lastCalled = performance.now();
                            result = func.apply(thisArg, args);
                            if (!timeoutId && !maxTimeoutId) {
                                args = thisArg = null;
                            }
                        }
                    }
                    else {
                        timeoutId = setTimeout(delayed, remaining);
                    }
                };
                var maxDelayed = function () {
                    if (timeoutId) {
                        clearTimeout(timeoutId);
                    }
                    maxTimeoutId = timeoutId = trailingCall = void 0;
                    if (trailing || (maxWait !== wait)) {
                        lastCalled = performance.now();
                        result = func.apply(thisArg, args);
                        if (!timeoutId && !maxTimeoutId) {
                            args = thisArg = null;
                        }
                    }
                };
                return function () {
                    args = arguments;
                    stamp = performance.now();
                    thisArg = this;
                    trailingCall = trailing && (timeoutId || !leading);
                    var isCalled = false;
                    var leadingCall = false;
                    if (maxWait === 0) {
                        leadingCall = leading && !timeoutId;
                    }
                    else {
                        if (!maxTimeoutId && !leading) {
                            lastCalled = stamp;
                        }
                        var remaining = maxWait - (stamp - lastCalled), isCalled_1 = remaining <= 0;
                        if (isCalled_1) {
                            if (maxTimeoutId) {
                                maxTimeoutId = clearTimeout(maxTimeoutId);
                            }
                            lastCalled = stamp;
                            result = func.apply(thisArg, args);
                        }
                        else if (!maxTimeoutId) {
                            maxTimeoutId = setTimeout(maxDelayed, remaining);
                        }
                    }
                    if (isCalled && timeoutId) {
                        timeoutId = clearTimeout(timeoutId);
                    }
                    else if (!timeoutId && wait !== maxWait) {
                        timeoutId = setTimeout(delayed, wait);
                    }
                    if (leadingCall) {
                        isCalled = true;
                        result = func.apply(thisArg, args);
                    }
                    if (isCalled && !timeoutId && !maxTimeoutId) {
                        args = thisArg = null;
                    }
                    return result;
                };
            }
            Utils.debounce = debounce;
        })(Utils = Core.Utils || (Core.Utils = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Utils;
        (function (Utils) {
            "use strict";
            var DataTable;
            (function (DataTable) {
                function typedColumn(t) {
                    return function (size) { return new t(size); };
                }
                DataTable.typedColumn = typedColumn;
                function customColumn() {
                    return function (size) { return new Array(size); };
                }
                DataTable.customColumn = customColumn;
                DataTable.stringColumn = function (size) { return new Array(size); };
                DataTable.stringNullColumn = function (size) { return new Array(size); };
                function builder(count) {
                    return new BuilderImpl(count);
                }
                DataTable.builder = builder;
                function ofDefinition(definition, count) {
                    var builder = DataTable.builder(count);
                    for (var _i = 0, _a = Object.keys(definition); _i < _a.length; _i++) {
                        var k = _a[_i];
                        if (!Object.prototype.hasOwnProperty.call(definition, k))
                            continue;
                        var col = definition[k];
                        if (col) {
                            builder.addColumn(k, col);
                        }
                    }
                    return builder.seal();
                }
                DataTable.ofDefinition = ofDefinition;
                function rowReader(table, indexer) {
                    var row = Object.create(null);
                    for (var _i = 0, _a = table.columns; _i < _a.length; _i++) {
                        var _c = _a[_i];
                        (function (c, row, idx, data) {
                            Object.defineProperty(row, c.name, { enumerable: true, configurable: false, get: function () { return data[idx.index]; } });
                        })(_c, row, indexer, table[_c.name]);
                    }
                    return row;
                }
                var TableImpl = /** @class */ (function () {
                    function TableImpl(count, srcColumns, srcData) {
                        this.__rowIndexer = { index: 0 };
                        this.count = count;
                        this.indices = new Int32Array(count);
                        this.columns = [];
                        for (var i = 0; i < count; i++) {
                            this.indices[i] = i;
                        }
                        for (var _i = 0, srcColumns_1 = srcColumns; _i < srcColumns_1.length; _i++) {
                            var col = srcColumns_1[_i];
                            var data = srcData[col.name];
                            if (Utils.ChunkedArray.is(data)) {
                                data = Utils.ChunkedArray.compact(data);
                            }
                            Object.defineProperty(this, col.name, { enumerable: true, configurable: false, writable: false, value: data });
                            this.columns[this.columns.length] = col;
                        }
                        this.__row = rowReader(this, this.__rowIndexer);
                    }
                    TableImpl.prototype.getBuilder = function (count) {
                        var b = new BuilderImpl(count);
                        for (var _i = 0, _a = this.columns; _i < _a.length; _i++) {
                            var c = _a[_i];
                            b.addColumn(c.name, c.creator);
                        }
                        return b;
                    };
                    TableImpl.prototype.getRawData = function () {
                        var _this = this;
                        return this.columns.map(function (c) { return _this[c.name]; });
                    };
                    TableImpl.prototype.getRow = function (i) {
                        this.__rowIndexer.index = i;
                        return this.__row;
                    };
                    return TableImpl;
                }());
                var BuilderImpl = /** @class */ (function () {
                    function BuilderImpl(count) {
                        this.columns = [];
                        this.count = count;
                    }
                    BuilderImpl.prototype.addColumn = function (name, creator) {
                        var c = creator(this.count);
                        Object.defineProperty(this, name, { enumerable: true, configurable: false, writable: false, value: c });
                        this.columns[this.columns.length] = { name: name, creator: creator };
                        return c;
                    };
                    BuilderImpl.prototype.addRawColumn = function (name, creator, data) {
                        var c = data;
                        Object.defineProperty(this, name, { enumerable: true, configurable: false, writable: false, value: c });
                        this.columns[this.columns.length] = { name: name, creator: creator };
                        return c;
                    };
                    BuilderImpl.prototype.getRawData = function () {
                        var _this = this;
                        return this.columns.map(function (c) { return _this[c.name]; });
                    };
                    /**
                     * This functions clones the table and defines all its column inside the constructor, hopefully making the JS engine
                     * use internal class instead of dictionary representation.
                     */
                    BuilderImpl.prototype.seal = function () {
                        return new TableImpl(this.count, this.columns, this);
                    };
                    return BuilderImpl;
                }());
            })(DataTable = Utils.DataTable || (Utils.DataTable = {}));
        })(Utils = Core.Utils || (Core.Utils = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Utils;
        (function (Utils) {
            "use strict";
            function integerSetToSortedTypedArray(set) {
                var array = new Int32Array(set.size);
                set.forEach(function (v, ctx) { ctx.array[ctx.index++] = v; }, { array: array, index: 0 });
                Array.prototype.sort.call(array, function (x, y) { return x - y; });
                return array;
            }
            Utils.integerSetToSortedTypedArray = integerSetToSortedTypedArray;
            /**
             * A a JS native array with the given size.
             */
            function makeNativeIntArray(size) {
                var arr = [];
                for (var i = 0; i < size; i++)
                    arr[i] = 0;
                return arr;
            }
            Utils.makeNativeIntArray = makeNativeIntArray;
            /**
             * A a JS native array with the given size.
             */
            function makeNativeFloatArray(size) {
                var arr = [];
                if (!size)
                    return arr;
                arr[0] = 0.1;
                for (var i = 0; i < size; i++)
                    arr[i] = 0;
                return arr;
            }
            Utils.makeNativeFloatArray = makeNativeFloatArray;
            var ChunkedArray;
            (function (ChunkedArray) {
                function is(x) {
                    return x.creator && x.chunkSize;
                }
                ChunkedArray.is = is;
                function add4(array, x, y, z, w) {
                    if (array.currentIndex >= array.chunkSize) {
                        array.currentIndex = 0;
                        array.current = array.creator(array.chunkSize);
                        array.parts[array.parts.length] = array.current;
                    }
                    array.current[array.currentIndex++] = x;
                    array.current[array.currentIndex++] = y;
                    array.current[array.currentIndex++] = z;
                    array.current[array.currentIndex++] = w;
                    return array.elementCount++;
                }
                ChunkedArray.add4 = add4;
                function add3(array, x, y, z) {
                    if (array.currentIndex >= array.chunkSize) {
                        array.currentIndex = 0;
                        array.current = array.creator(array.chunkSize);
                        array.parts[array.parts.length] = array.current;
                    }
                    array.current[array.currentIndex++] = x;
                    array.current[array.currentIndex++] = y;
                    array.current[array.currentIndex++] = z;
                    return array.elementCount++;
                }
                ChunkedArray.add3 = add3;
                function add2(array, x, y) {
                    if (array.currentIndex >= array.chunkSize) {
                        array.currentIndex = 0;
                        array.current = array.creator(array.chunkSize);
                        array.parts[array.parts.length] = array.current;
                    }
                    array.current[array.currentIndex++] = x;
                    array.current[array.currentIndex++] = y;
                    return array.elementCount++;
                }
                ChunkedArray.add2 = add2;
                function add(array, x) {
                    if (array.currentIndex >= array.chunkSize) {
                        array.currentIndex = 0;
                        array.current = array.creator(array.chunkSize);
                        array.parts[array.parts.length] = array.current;
                    }
                    array.current[array.currentIndex++] = x;
                    return array.elementCount++;
                }
                ChunkedArray.add = add;
                function compact(array) {
                    var ret = array.creator(array.elementSize * array.elementCount), offset = (array.parts.length - 1) * array.chunkSize, offsetInner = 0, part;
                    if (array.parts.length === 1 && array.chunkSize === array.elementCount) {
                        return array.parts[0];
                    }
                    if (array.parts.length > 1) {
                        if (array.parts[0].buffer) {
                            for (var i = 0; i < array.parts.length - 1; i++) {
                                ret.set(array.parts[i], array.chunkSize * i);
                            }
                        }
                        else {
                            for (var i = 0; i < array.parts.length - 1; i++) {
                                offsetInner = array.chunkSize * i;
                                part = array.parts[i];
                                for (var j = 0; j < array.chunkSize; j++) {
                                    ret[offsetInner + j] = part[j];
                                }
                            }
                        }
                    }
                    if (array.current.buffer && array.currentIndex >= array.chunkSize) {
                        ret.set(array.current, array.chunkSize * (array.parts.length - 1));
                    }
                    else {
                        for (var i = 0; i < array.currentIndex; i++) {
                            ret[offset + i] = array.current[i];
                        }
                    }
                    return ret;
                }
                ChunkedArray.compact = compact;
                function forVertex3D(chunkVertexCount) {
                    if (chunkVertexCount === void 0) { chunkVertexCount = 262144; }
                    return create(function (size) { return new Float32Array(size); }, chunkVertexCount, 3);
                }
                ChunkedArray.forVertex3D = forVertex3D;
                function forIndexBuffer(chunkIndexCount) {
                    if (chunkIndexCount === void 0) { chunkIndexCount = 262144; }
                    return create(function (size) { return new Uint32Array(size); }, chunkIndexCount, 3);
                }
                ChunkedArray.forIndexBuffer = forIndexBuffer;
                function forTokenIndices(chunkTokenCount) {
                    if (chunkTokenCount === void 0) { chunkTokenCount = 131072; }
                    return create(function (size) { return new Int32Array(size); }, chunkTokenCount, 2);
                }
                ChunkedArray.forTokenIndices = forTokenIndices;
                function forIndices(chunkTokenCount) {
                    if (chunkTokenCount === void 0) { chunkTokenCount = 131072; }
                    return create(function (size) { return new Int32Array(size); }, chunkTokenCount, 1);
                }
                ChunkedArray.forIndices = forIndices;
                function forInt32(chunkSize) {
                    if (chunkSize === void 0) { chunkSize = 131072; }
                    return create(function (size) { return new Int32Array(size); }, chunkSize, 1);
                }
                ChunkedArray.forInt32 = forInt32;
                function forFloat32(chunkSize) {
                    if (chunkSize === void 0) { chunkSize = 131072; }
                    return create(function (size) { return new Float32Array(size); }, chunkSize, 1);
                }
                ChunkedArray.forFloat32 = forFloat32;
                function forArray(chunkSize) {
                    if (chunkSize === void 0) { chunkSize = 131072; }
                    return create(function (size) { return []; }, chunkSize, 1);
                }
                ChunkedArray.forArray = forArray;
                function create(creator, chunkElementCount, elementSize) {
                    chunkElementCount = chunkElementCount | 0;
                    if (chunkElementCount <= 0)
                        chunkElementCount = 1;
                    var chunkSize = chunkElementCount * elementSize;
                    var current = creator(chunkSize);
                    return {
                        elementSize: elementSize,
                        chunkSize: chunkSize,
                        creator: creator,
                        current: current,
                        parts: [current],
                        currentIndex: 0,
                        elementCount: 0
                    };
                }
                ChunkedArray.create = create;
            })(ChunkedArray = Utils.ChunkedArray || (Utils.ChunkedArray = {}));
            var ArrayBuilder;
            (function (ArrayBuilder) {
                function add3(array, x, y, z) {
                    var a = array.array;
                    a[array.currentIndex++] = x;
                    a[array.currentIndex++] = y;
                    a[array.currentIndex++] = z;
                    array.elementCount++;
                }
                ArrayBuilder.add3 = add3;
                function add2(array, x, y) {
                    var a = array.array;
                    a[array.currentIndex++] = x;
                    a[array.currentIndex++] = y;
                    array.elementCount++;
                }
                ArrayBuilder.add2 = add2;
                function add(array, x) {
                    array.array[array.currentIndex++] = x;
                    array.elementCount++;
                }
                ArrayBuilder.add = add;
                function forVertex3D(count) {
                    return create(function (size) { return new Float32Array(size); }, count, 3);
                }
                ArrayBuilder.forVertex3D = forVertex3D;
                function forIndexBuffer(count) {
                    return create(function (size) { return new Int32Array(size); }, count, 3);
                }
                ArrayBuilder.forIndexBuffer = forIndexBuffer;
                function forTokenIndices(count) {
                    return create(function (size) { return new Int32Array(size); }, count, 2);
                }
                ArrayBuilder.forTokenIndices = forTokenIndices;
                function forIndices(count) {
                    return create(function (size) { return new Int32Array(size); }, count, 1);
                }
                ArrayBuilder.forIndices = forIndices;
                function forInt32(count) {
                    return create(function (size) { return new Int32Array(size); }, count, 1);
                }
                ArrayBuilder.forInt32 = forInt32;
                function forFloat32(count) {
                    return create(function (size) { return new Float32Array(size); }, count, 1);
                }
                ArrayBuilder.forFloat32 = forFloat32;
                function forArray(count) {
                    return create(function (size) { return []; }, count, 1);
                }
                ArrayBuilder.forArray = forArray;
                function create(creator, chunkElementCount, elementSize) {
                    chunkElementCount = chunkElementCount | 0;
                    return {
                        array: creator(chunkElementCount * elementSize),
                        currentIndex: 0,
                        elementCount: 0
                    };
                }
                ArrayBuilder.create = create;
            })(ArrayBuilder = Utils.ArrayBuilder || (Utils.ArrayBuilder = {}));
            function UniqueArray() {
                return { _set: Utils.FastSet.create(), array: [] };
            }
            Utils.UniqueArray = UniqueArray;
            (function (UniqueArray) {
                function add(_a, e) {
                    var _set = _a._set, array = _a.array;
                    if (!_set.has(e)) {
                        _set.add(e);
                        array[array.length] = e;
                    }
                }
                UniqueArray.add = add;
            })(UniqueArray = Utils.UniqueArray || (Utils.UniqueArray = {}));
        })(Utils = Core.Utils || (Core.Utils = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Utils;
        (function (Utils) {
            "use strict";
            var PerformanceHelper;
            (function (PerformanceHelper) {
                PerformanceHelper.perfGetTime = (function () {
                    if (typeof window !== 'undefined' && window.performance) {
                        return function () { return window.performance.now(); };
                    }
                    else if (typeof process !== 'undefined' && process.hrtime !== 'undefined') {
                        return function () {
                            var t = process.hrtime();
                            return t[0] * 1000 + t[1] / 1000000;
                        };
                    }
                    else {
                        return function () { return +new Date(); };
                    }
                })();
            })(PerformanceHelper || (PerformanceHelper = {}));
            var PerformanceMonitor = /** @class */ (function () {
                function PerformanceMonitor() {
                    this.starts = Utils.FastMap.create();
                    this.ends = Utils.FastMap.create();
                }
                PerformanceMonitor.currentTime = function () {
                    return PerformanceHelper.perfGetTime();
                };
                PerformanceMonitor.prototype.start = function (name) {
                    this.starts.set(name, PerformanceHelper.perfGetTime());
                };
                PerformanceMonitor.prototype.end = function (name) {
                    this.ends.set(name, PerformanceHelper.perfGetTime());
                };
                PerformanceMonitor.format = function (t) {
                    if (isNaN(t))
                        return 'n/a';
                    var h = Math.floor(t / (60 * 60 * 1000)), m = Math.floor(t / (60 * 1000) % 60), s = Math.floor(t / 1000 % 60), ms = Math.floor(t % 1000).toString();
                    while (ms.length < 3)
                        ms = "0" + ms;
                    if (h > 0)
                        return h + "h" + m + "m" + s + "." + ms + "s";
                    if (m > 0)
                        return m + "m" + s + "." + ms + "s";
                    if (s > 0)
                        return s + "." + ms + "s";
                    return t.toFixed(0) + "ms";
                };
                PerformanceMonitor.prototype.formatTime = function (name) {
                    return PerformanceMonitor.format(this.time(name));
                };
                PerformanceMonitor.prototype.formatTimeSum = function () {
                    var names = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        names[_i] = arguments[_i];
                    }
                    return PerformanceMonitor.format(this.timeSum.apply(this, names));
                };
                // return the time in milliseconds and removes them from the cache.
                PerformanceMonitor.prototype.time = function (name) {
                    var start = this.starts.get(name), end = this.ends.get(name);
                    this.starts.delete(name);
                    this.ends.delete(name);
                    return end - start;
                };
                PerformanceMonitor.prototype.timeSum = function () {
                    var _this = this;
                    var names = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        names[_i] = arguments[_i];
                    }
                    var t = 0;
                    for (var _a = 0, _b = names.map(function (n) { return _this.ends.get(n) - _this.starts.get(n); }); _a < _b.length; _a++) {
                        var m = _b[_a];
                        t += m;
                    }
                    return t;
                };
                return PerformanceMonitor;
            }());
            Utils.PerformanceMonitor = PerformanceMonitor;
        })(Utils = Core.Utils || (Core.Utils = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            "use strict";
            var FormatInfo;
            (function (FormatInfo) {
                function is(o) {
                    return o.name && o.parse;
                }
                FormatInfo.is = is;
                function fromShortcut(all, name) {
                    name = name.toLowerCase().trim();
                    for (var _i = 0, all_1 = all; _i < all_1.length; _i++) {
                        var f = all_1[_i];
                        for (var _a = 0, _b = f.shortcuts; _a < _b.length; _a++) {
                            var s = _b[_a];
                            if (s.toLowerCase() === name)
                                return f;
                        }
                    }
                    return void 0;
                }
                FormatInfo.fromShortcut = fromShortcut;
                function formatRegExp(info) {
                    return new RegExp(info.extensions.map(function (e) { return "(\\" + e + ")"; }).join('|') + '(\\.gz){0,1}$', 'i');
                }
                FormatInfo.formatRegExp = formatRegExp;
                function formatFileFilters(all) {
                    return all.map(function (info) { return info.extensions.map(function (e) { return e + "," + e + ".gz"; }).join(','); }).join(',');
                }
                FormatInfo.formatFileFilters = formatFileFilters;
                function getFormat(filename, all) {
                    for (var _i = 0, all_2 = all; _i < all_2.length; _i++) {
                        var f = all_2[_i];
                        if (formatRegExp(f).test(filename))
                            return f;
                    }
                    return void 0;
                }
                FormatInfo.getFormat = getFormat;
            })(FormatInfo = Formats.FormatInfo || (Formats.FormatInfo = {}));
            var ParserResult;
            (function (ParserResult) {
                function error(message, line) {
                    if (line === void 0) { line = -1; }
                    return new ParserError(message, line);
                }
                ParserResult.error = error;
                function success(result, warnings) {
                    if (warnings === void 0) { warnings = []; }
                    return new ParserSuccess(result, warnings);
                }
                ParserResult.success = success;
            })(ParserResult = Formats.ParserResult || (Formats.ParserResult = {}));
            var ParserError = /** @class */ (function () {
                function ParserError(message, line) {
                    this.message = message;
                    this.line = line;
                    this.isError = true;
                }
                ParserError.prototype.toString = function () {
                    if (this.line >= 0) {
                        return "[Line " + this.line + "] " + this.message;
                    }
                    return this.message;
                };
                return ParserError;
            }());
            Formats.ParserError = ParserError;
            var ParserSuccess = /** @class */ (function () {
                function ParserSuccess(result, warnings) {
                    this.result = result;
                    this.warnings = warnings;
                    this.isError = false;
                }
                return ParserSuccess;
            }());
            Formats.ParserSuccess = ParserSuccess;
            var TokenIndexBuilder;
            (function (TokenIndexBuilder) {
                function resize(builder) {
                    // scale the size using golden ratio, because why not.
                    var newBuffer = new Int32Array(Math.round(1.61 * builder.tokens.length));
                    newBuffer.set(builder.tokens);
                    builder.tokens = newBuffer;
                    builder.tokensLenMinus2 = newBuffer.length - 2;
                }
                function addToken(builder, start, end) {
                    if (builder.count >= builder.tokensLenMinus2) {
                        resize(builder);
                    }
                    builder.tokens[builder.count++] = start;
                    builder.tokens[builder.count++] = end;
                }
                TokenIndexBuilder.addToken = addToken;
                function create(size) {
                    return {
                        tokensLenMinus2: Math.round(size) - 2,
                        count: 0,
                        tokens: new Int32Array(size)
                    };
                }
                TokenIndexBuilder.create = create;
            })(TokenIndexBuilder = Formats.TokenIndexBuilder || (Formats.TokenIndexBuilder = {}));
            var ShortStringPool;
            (function (ShortStringPool) {
                function create() { return Object.create(null); }
                ShortStringPool.create = create;
                function get(pool, str) {
                    if (str.length > 6)
                        return str;
                    var value = pool[str];
                    if (value !== void 0)
                        return value;
                    pool[str] = str;
                    return str;
                }
                ShortStringPool.get = get;
            })(ShortStringPool = Formats.ShortStringPool || (Formats.ShortStringPool = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Molecule;
            (function (Molecule) {
                var mmCIF;
                (function (mmCIF) {
                    "use strict";
                    var Defaults;
                    (function (Defaults) {
                        Defaults.ElementSymbol = 'X';
                        Defaults.ResidueName = 'UNK';
                        Defaults.AsymId = '';
                        Defaults.EntityId = '1';
                        Defaults.ModelId = '1';
                    })(Defaults || (Defaults = {}));
                    function getTransform(category, matrixField, translationField, row) {
                        var ret = Core.Geometry.LinearAlgebra.Matrix4.identity(), i, j;
                        for (i = 1; i <= 3; i++) {
                            for (j = 1; j <= 3; j++) {
                                Core.Geometry.LinearAlgebra.Matrix4.setValue(ret, i - 1, j - 1, category.getColumn(matrixField + "[" + i + "][" + j + "]").getFloat(row));
                            }
                            Core.Geometry.LinearAlgebra.Matrix4.setValue(ret, i - 1, 3, category.getColumn(translationField + "[" + i + "]").getFloat(row));
                        }
                        return ret;
                    }
                    function getModelEndRow(startRow, rowCount, modelNum) {
                        var i = 0;
                        if (!modelNum || !modelNum.isDefined)
                            return rowCount;
                        for (i = startRow + 1; i < rowCount; i++) {
                            if (!modelNum.areValuesEqual(i - 1, i))
                                break;
                        }
                        return i;
                    }
                    var AtomSiteColumns = [
                        'id',
                        'Cartn_x',
                        'Cartn_y',
                        'Cartn_z',
                        'label_atom_id',
                        'type_symbol',
                        'occupancy',
                        'B_iso_or_equiv',
                        'auth_atom_id',
                        'label_alt_id',
                        'label_comp_id',
                        'label_seq_id',
                        'label_asym_id',
                        'auth_comp_id',
                        'auth_seq_id',
                        'auth_asym_id',
                        'group_PDB',
                        'label_entity_id',
                        'pdbx_PDB_ins_code',
                        'pdbx_PDB_model_num'
                    ];
                    function getAtomSiteColumns(category) {
                        var ret = Core.Utils.FastMap.create();
                        for (var _a = 0, AtomSiteColumns_1 = AtomSiteColumns; _a < AtomSiteColumns_1.length; _a++) {
                            var c = AtomSiteColumns_1[_a];
                            ret.set(c, category.getColumn(c));
                        }
                        return ret;
                    }
                    function buildModelAtomTable(startRow, rowCount, columns) {
                        var endRow = getModelEndRow(startRow, rowCount, columns.get('pdbx_PDB_model_num'));
                        var atoms = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Atoms, endRow - startRow), positions = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Positions, endRow - startRow), pX = positions.x, pXCol = columns.get('Cartn_x'), pY = positions.y, pYCol = columns.get('Cartn_y'), pZ = positions.z, pZCol = columns.get('Cartn_z'), id = atoms.id, idCol = columns.get('id'), altLoc = atoms.altLoc, altLocCol = columns.get('label_alt_id'), rowIndex = atoms.rowIndex, residueIndex = atoms.residueIndex, chainIndex = atoms.chainIndex, entityIndex = atoms.entityIndex, name = atoms.name, nameCol = columns.get('label_atom_id'), elementSymbol = atoms.elementSymbol, elementSymbolCol = columns.get('type_symbol'), occupancy = atoms.occupancy, occupancyCol = columns.get('occupancy'), tempFactor = atoms.tempFactor, tempFactorCol = columns.get('B_iso_or_equiv'), authName = atoms.authName, authNameCol = columns.get('auth_atom_id');
                        var asymIdCol = columns.get('label_asym_id'), entityIdCol = columns.get('label_entity_id'), insCodeCol = columns.get('pdbx_PDB_ins_code'), authResSeqNumberCol = columns.get('auth_seq_id'), modelNumCol = columns.get('pdbx_PDB_model_num'), numChains = 0, numResidues = 0, numEntities = 0;
                        var prev = startRow;
                        for (var row = startRow; row < endRow; row++) {
                            var index = row - startRow;
                            id[index] = idCol.getInteger(row);
                            pX[index] = pXCol.getFloat(row);
                            pY[index] = pYCol.getFloat(row);
                            pZ[index] = pZCol.getFloat(row);
                            elementSymbol[index] = elementSymbolCol.getString(row) || Defaults.ElementSymbol;
                            name[index] = nameCol.getString(row) || elementSymbol[index];
                            authName[index] = authNameCol.getString(row) || name[index];
                            altLoc[index] = altLocCol.getString(row);
                            occupancy[index] = occupancyCol.getFloat(row);
                            tempFactor[index] = tempFactorCol.getFloat(row);
                            var newChain = false;
                            var newResidue = !authResSeqNumberCol.areValuesEqual(prev, row) || !insCodeCol.areValuesEqual(prev, row);
                            if (!asymIdCol.areValuesEqual(prev, row)) {
                                newChain = true;
                                newResidue = true;
                            }
                            if (!entityIdCol.areValuesEqual(prev, row)) {
                                numEntities++;
                                newChain = true;
                                newResidue = true;
                            }
                            if (newResidue)
                                numResidues++;
                            if (newChain)
                                numChains++;
                            rowIndex[index] = row;
                            residueIndex[index] = numResidues;
                            chainIndex[index] = numChains;
                            entityIndex[index] = numEntities;
                            prev = row;
                        }
                        var modelId = !modelNumCol.isDefined ? Defaults.ModelId : modelNumCol.getString(startRow) || Defaults.ModelId;
                        return { atoms: atoms, positions: positions, modelId: modelId, endRow: endRow };
                    }
                    function buildStructure(columns, atoms) {
                        var count = atoms.count, residueIndexCol = atoms.residueIndex, chainIndexCol = atoms.chainIndex, entityIndexCol = atoms.entityIndex;
                        var residues = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Residues, atoms.residueIndex[atoms.count - 1] + 1), chains = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Chains, atoms.chainIndex[atoms.count - 1] + 1), entities = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Entities, atoms.entityIndex[atoms.count - 1] + 1);
                        var residueName = residues.name, residueSeqNumber = residues.seqNumber, residueAsymId = residues.asymId, residueAuthName = residues.authName, residueAuthSeqNumber = residues.authSeqNumber, residueAuthAsymId = residues.authAsymId, residueInsertionCode = residues.insCode, residueEntityId = residues.entityId, residueIsHet = residues.isHet, residueAtomStartIndex = residues.atomStartIndex, residueAtomEndIndex = residues.atomEndIndex, residueChainIndex = residues.chainIndex, residueEntityIndex = residues.entityIndex;
                        var chainAsymId = chains.asymId, chainEntityId = chains.entityId, chainAuthAsymId = chains.authAsymId, chainAtomStartIndex = chains.atomStartIndex, chainAtomEndIndex = chains.atomEndIndex, chainResidueStartIndex = chains.residueStartIndex, chainResidueEndIndex = chains.residueEndIndex, chainEntityIndex = chains.entityIndex;
                        var entityId = entities.entityId, entityType = entities.type, entityAtomStartIndex = entities.atomStartIndex, entityAtomEndIndex = entities.atomEndIndex, entityResidueStartIndex = entities.residueStartIndex, entityResidueEndIndex = entities.residueEndIndex, entityChainStartIndex = entities.chainStartIndex, entityChainEndIndex = entities.chainEndIndex;
                        var resNameCol = columns.get('label_comp_id'), resSeqNumberCol = columns.get('label_seq_id'), asymIdCol = columns.get('label_asym_id'), authResNameCol = columns.get('auth_comp_id'), authResSeqNumberCol = columns.get('auth_seq_id'), authAsymIdCol = columns.get('auth_asym_id'), isHetCol = columns.get('group_PDB'), entityCol = columns.get('label_entity_id'), insCodeCol = columns.get('pdbx_PDB_ins_code');
                        var residueStart = 0, chainStart = 0, entityStart = 0, entityChainStart = 0, entityResidueStart = 0, chainResidueStart = 0, currentResidue = 0, currentChain = 0, currentEntity = 0;
                        var i = 0;
                        for (i = 0; i < count; i++) {
                            if (residueIndexCol[i] !== residueIndexCol[residueStart]) {
                                residueName[currentResidue] = resNameCol.getString(residueStart) || Defaults.ResidueName;
                                residueSeqNumber[currentResidue] = resSeqNumberCol.getInteger(residueStart);
                                residueAsymId[currentResidue] = asymIdCol.getString(residueStart) || Defaults.AsymId;
                                residueAuthName[currentResidue] = authResNameCol.getString(residueStart) || residueName[currentResidue];
                                residueAuthSeqNumber[currentResidue] = authResSeqNumberCol.getInteger(residueStart);
                                residueAuthAsymId[currentResidue] = authAsymIdCol.getString(residueStart) || residueAsymId[currentResidue];
                                residueInsertionCode[currentResidue] = insCodeCol.getString(residueStart);
                                residueEntityId[currentResidue] = entityCol.getString(residueStart) || Defaults.EntityId;
                                residueIsHet[currentResidue] = isHetCol.stringEquals(residueStart, 'HETATM') ? 1 : 0;
                                residueAtomStartIndex[currentResidue] = residueStart;
                                residueAtomEndIndex[currentResidue] = i;
                                residueChainIndex[currentResidue] = currentChain;
                                residueEntityIndex[currentResidue] = currentEntity;
                                currentResidue++;
                                residueStart = i;
                            }
                            if (chainIndexCol[i] !== chainIndexCol[chainStart]) {
                                chainAsymId[currentChain] = asymIdCol.getString(chainStart) || Defaults.AsymId;
                                chainAuthAsymId[currentChain] = authAsymIdCol.getString(chainStart) || chainAsymId[currentChain];
                                chainEntityId[currentChain] = entityCol.getString(chainStart) || Defaults.EntityId;
                                chainResidueStartIndex[currentChain] = chainResidueStart;
                                chainResidueEndIndex[currentChain] = currentResidue;
                                chainAtomStartIndex[currentChain] = chainStart;
                                chainAtomEndIndex[currentChain] = i;
                                chainEntityIndex[currentChain] = currentEntity;
                                currentChain++;
                                chainStart = i;
                                chainResidueStart = currentResidue;
                            }
                            if (entityIndexCol[i] !== entityIndexCol[entityStart]) {
                                entityId[currentEntity] = entityCol.getString(entityStart) || Defaults.EntityId;
                                entityType[currentEntity] = 'unknown';
                                entityAtomStartIndex[currentEntity] = entityStart;
                                entityAtomEndIndex[currentEntity] = i;
                                entityResidueStartIndex[currentEntity] = entityResidueStart;
                                entityResidueEndIndex[currentEntity] = currentResidue;
                                entityChainStartIndex[currentEntity] = entityChainStart;
                                entityChainEndIndex[currentEntity] = currentChain;
                                currentEntity++;
                                entityStart = i;
                                entityChainStart = currentChain;
                                entityResidueStart = currentResidue;
                            }
                        }
                        // entity
                        entityId[currentEntity] = entityCol.getString(entityStart) || Defaults.EntityId;
                        entityType[currentEntity] = 'unknown';
                        entityAtomStartIndex[currentEntity] = entityStart;
                        entityAtomEndIndex[currentEntity] = i;
                        entityResidueStartIndex[currentEntity] = entityResidueStart;
                        entityResidueEndIndex[currentEntity] = currentResidue + 1;
                        entityChainStartIndex[currentEntity] = entityChainStart;
                        entityChainEndIndex[currentEntity] = currentChain + 1;
                        // chain
                        chainAsymId[currentChain] = asymIdCol.getString(chainStart) || Defaults.AsymId;
                        chainAuthAsymId[currentChain] = authAsymIdCol.getString(chainStart) || chainAsymId[currentChain];
                        chainEntityId[currentChain] = entityCol.getString(chainStart) || Defaults.EntityId;
                        chainResidueStartIndex[currentChain] = chainResidueStart;
                        chainResidueEndIndex[currentChain] = currentResidue + 1;
                        chainAtomStartIndex[currentChain] = chainStart;
                        chainAtomEndIndex[currentChain] = i;
                        chainEntityIndex[currentChain] = currentEntity;
                        // residue
                        residueName[currentResidue] = resNameCol.getString(residueStart) || Defaults.ResidueName;
                        residueSeqNumber[currentResidue] = resSeqNumberCol.getInteger(residueStart);
                        residueAsymId[currentResidue] = asymIdCol.getString(residueStart) || Defaults.AsymId;
                        residueAuthName[currentResidue] = authResNameCol.getString(residueStart) || residueName[currentResidue];
                        residueAuthSeqNumber[currentResidue] = authResSeqNumberCol.getInteger(residueStart);
                        residueAuthAsymId[currentResidue] = authAsymIdCol.getString(residueStart) || residueAsymId[currentResidue];
                        residueInsertionCode[currentResidue] = insCodeCol.getString(residueStart);
                        residueAtomStartIndex[currentResidue] = residueStart;
                        residueAtomEndIndex[currentResidue] = i;
                        residueChainIndex[currentResidue] = currentChain;
                        residueEntityIndex[currentResidue] = currentEntity;
                        residueIsHet[currentResidue] = isHetCol.stringEquals(residueStart, 'HETATM') ? 1 : 0;
                        return { residues: residues, chains: chains, entities: entities };
                    }
                    function assignEntityTypes(category, entities) {
                        var i;
                        if (!category) {
                            return;
                        }
                        var data = {}, typeCol = category.getColumn('type'), idCol = category.getColumn('id');
                        for (i = 0; i < category.rowCount; i++) {
                            var t = (typeCol.getString(i) || '').toLowerCase();
                            var eId = idCol.getString(i) || Defaults.EntityId;
                            switch (t) {
                                case 'polymer':
                                case 'non-polymer':
                                case 'water':
                                    data[eId] = t;
                                    break;
                                default:
                                    data[eId] = 'unknown';
                                    break;
                            }
                        }
                        for (i = 0; i < entities.count; i++) {
                            var et = data[entities.entityId[i]];
                            if (et !== void 0) {
                                entities.type[i] = et;
                            }
                        }
                    }
                    function residueIdfromColumns(row, asymId, seqNum, insCode) {
                        return new Core.Structure.PolyResidueIdentifier(asymId.getString(row) || Defaults.AsymId, seqNum.getInteger(row), insCode.getString(row));
                    }
                    var aminoAcidNames = { 'ALA': true, 'ARG': true, 'ASP': true, 'CYS': true, 'GLN': true, 'GLU': true, 'GLY': true, 'HIS': true, 'ILE': true, 'LEU': true, 'LYS': true, 'MET': true, 'PHE': true, 'PRO': true, 'SER': true, 'THR': true, 'TRP': true, 'TYR': true, 'VAL': true, 'ASN': true, 'PYL': true, 'SEC': true };
                    function isResidueAminoSeq(atoms, residues, entities, index) {
                        if (entities.type[residues.entityIndex[index]] !== 'polymer')
                            return false;
                        //if (mmCif.aminoAcidNames[residues.name[index]]) return true;
                        var ca = false, o = false, names = atoms.name, assigned = 0;
                        for (var i = residues.atomStartIndex[index], max = residues.atomEndIndex[index]; i < max; i++) {
                            var n = names[i];
                            if (!ca && n === 'CA') {
                                ca = true;
                                assigned++;
                            }
                            else if (!o && n === 'O') {
                                o = true;
                                assigned++;
                            }
                            if (assigned === 2)
                                break;
                        }
                        return (ca && o) || (ca && !residues.isHet[index]);
                    }
                    function isResidueNucleotide(atoms, residues, entities, index) {
                        if (aminoAcidNames[residues.name[index]] || entities.type[residues.entityIndex[index]] !== 'polymer')
                            return false;
                        var names = atoms.name, assigned = 0;
                        var start = residues.atomStartIndex[index], end = residues.atomEndIndex[index];
                        // test for single atom instances
                        if (end - start === 1 && !residues.isHet[start] && names[start] === 'P') {
                            return true;
                        }
                        for (var i = start; i < end; i++) {
                            var n = names[i];
                            if (n === "O5'" || n === "C3'" || n === "N3" || n === "P") {
                                assigned++;
                            }
                            if (assigned >= 3) {
                                return true;
                            }
                        }
                        return false;
                    }
                    function analyzeSecondaryStructure(atoms, residues, entities, start, end, elements) {
                        var asymId = residues.asymId, entityIndex = residues.entityIndex, currentType = 0 /* None */, currentElementStartIndex = start, currentResidueIndex = start, residueCount = end;
                        while (currentElementStartIndex < residueCount) {
                            if (isResidueNucleotide(atoms, residues, entities, currentElementStartIndex)) {
                                currentResidueIndex = currentElementStartIndex + 1;
                                while (currentResidueIndex < residueCount
                                    && asymId[currentElementStartIndex] === asymId[currentResidueIndex]
                                    && entityIndex[currentElementStartIndex] === entityIndex[currentResidueIndex]
                                    && isResidueNucleotide(atoms, residues, entities, currentResidueIndex)) {
                                    currentResidueIndex++;
                                }
                                currentType = 5 /* Strand */;
                            }
                            else if (isResidueAminoSeq(atoms, residues, entities, currentElementStartIndex)) {
                                currentResidueIndex = currentElementStartIndex + 1;
                                while (currentResidueIndex < residueCount
                                    && asymId[currentElementStartIndex] === asymId[currentResidueIndex]
                                    && entityIndex[currentElementStartIndex] === entityIndex[currentResidueIndex]
                                    && isResidueAminoSeq(atoms, residues, entities, currentResidueIndex)) {
                                    currentResidueIndex++;
                                }
                                currentType = 4 /* AminoSeq */;
                            }
                            else {
                                currentResidueIndex = currentElementStartIndex + 1;
                                while (currentResidueIndex < residueCount
                                    && asymId[currentElementStartIndex] === asymId[currentResidueIndex]
                                    && entityIndex[currentElementStartIndex] === entityIndex[currentResidueIndex]
                                    && !isResidueNucleotide(atoms, residues, entities, currentResidueIndex)
                                    && !isResidueAminoSeq(atoms, residues, entities, currentResidueIndex)) {
                                    currentResidueIndex++;
                                }
                                currentType = 0 /* None */;
                            }
                            var e = new Core.Structure.SecondaryStructureElement(currentType, new Core.Structure.PolyResidueIdentifier(residues.asymId[currentElementStartIndex], residues.seqNumber[currentElementStartIndex], residues.insCode[currentElementStartIndex]), new Core.Structure.PolyResidueIdentifier(residues.asymId[currentResidueIndex - 1], residues.seqNumber[currentResidueIndex - 1], residues.insCode[currentResidueIndex - 1]));
                            e.startResidueIndex = currentElementStartIndex;
                            e.endResidueIndex = currentResidueIndex;
                            elements[elements.length] = e;
                            currentElementStartIndex = currentResidueIndex;
                        }
                    }
                    function splitNonconsecutiveSecondaryStructure(residues, elements) {
                        var ret = [];
                        var authSeqNumber = residues.authSeqNumber;
                        for (var _a = 0, elements_1 = elements; _a < elements_1.length; _a++) {
                            var s = elements_1[_a];
                            var partStart = s.startResidueIndex;
                            var end = s.endResidueIndex - 1;
                            for (var i = s.startResidueIndex; i < end; i++) {
                                if (authSeqNumber[i + 1] - authSeqNumber[i] === 1)
                                    continue;
                                var e = new Core.Structure.SecondaryStructureElement(s.type, s.startResidueId, s.endResidueId, s.info);
                                e.startResidueIndex = partStart;
                                e.endResidueIndex = i + 1;
                                ret[ret.length] = e;
                                partStart = i + 1;
                            }
                            if (partStart === s.startResidueIndex) {
                                ret[ret.length] = s;
                            }
                            else {
                                var e = new Core.Structure.SecondaryStructureElement(s.type, s.startResidueId, s.endResidueId, s.info);
                                e.startResidueIndex = partStart;
                                e.endResidueIndex = s.endResidueIndex;
                                ret[ret.length] = e;
                            }
                        }
                        return ret;
                    }
                    function updateSSIndicesAndFilterEmpty(elements, structure) {
                        var residues = structure.residues, count = residues.count, asymId = residues.asymId, seqNumber = residues.seqNumber, insCode = residues.insCode, currentElement = void 0, key = '', starts = Core.Utils.FastMap.create(), ends = Core.Utils.FastMap.create();
                        for (var _a = 0, elements_2 = elements; _a < elements_2.length; _a++) {
                            var e = elements_2[_a];
                            key = e.startResidueId.asymId + ' ' + e.startResidueId.seqNumber;
                            if (e.startResidueId.insCode)
                                key += ' ' + e.startResidueId.insCode;
                            starts.set(key, e);
                            key = e.endResidueId.asymId + ' ' + e.endResidueId.seqNumber;
                            if (e.endResidueId.insCode)
                                key += ' ' + e.endResidueId.insCode;
                            ends.set(key, e);
                        }
                        for (var i = 0; i < count; i++) {
                            key = asymId[i] + ' ' + seqNumber[i];
                            if (insCode[i])
                                key += ' ' + insCode[i];
                            currentElement = starts.get(key);
                            if (currentElement) {
                                currentElement.startResidueIndex = i;
                                currentElement.endResidueIndex = i + 1;
                            }
                            currentElement = ends.get(key);
                            if (currentElement) {
                                if (currentElement.startResidueIndex < 0)
                                    currentElement.startResidueIndex = i;
                                currentElement.endResidueIndex = i + 1;
                            }
                        }
                        if (currentElement) {
                            currentElement.endResidueIndex = count;
                        }
                        var nonEmpty = [];
                        for (var _b = 0, elements_3 = elements; _b < elements_3.length; _b++) {
                            var e = elements_3[_b];
                            if (e.startResidueIndex < 0 || e.endResidueIndex < 0)
                                continue;
                            if (e.type === 3 /* Sheet */ && e.length < 3)
                                continue;
                            if (e.endResidueIndex >= 0 && e.startResidueIndex >= 0)
                                nonEmpty[nonEmpty.length] = e;
                        }
                        nonEmpty.sort(function (a, b) { return a.startResidueIndex - b.startResidueIndex; });
                        // fix one-off "overlaps" for helices
                        for (var i = 0; i < nonEmpty.length - 1; i++) {
                            if (nonEmpty[i + 1].startResidueIndex - nonEmpty[i].endResidueIndex === -1) {
                                nonEmpty[i + 1].startResidueIndex++;
                            }
                        }
                        if (!nonEmpty.length)
                            return nonEmpty;
                        var ret = [nonEmpty[0]];
                        // handle overlapping structures.
                        for (var i = 1; i < nonEmpty.length; i++) {
                            var a = ret[ret.length - 1], b = nonEmpty[i];
                            if (b.startResidueIndex < a.endResidueIndex) {
                                handleSecondaryStructureCollision(a, b);
                            }
                            else {
                                ret[ret.length] = b;
                            }
                        }
                        return ret;
                    }
                    function handleSecondaryStructureCollision(a, b) {
                        if (b.endResidueIndex > a.endResidueIndex) {
                            a.endResidueIndex = b.endResidueIndex;
                        }
                    }
                    function getSecondaryStructureInfo(data, atoms, structure) {
                        var input = [], elements = [];
                        var _struct_conf = data.getCategory('_struct_conf'), _struct_sheet_range = data.getCategory('_struct_sheet_range'), i;
                        if (_struct_conf) {
                            var type_id_col = _struct_conf.getColumn('conf_type_id');
                            if (type_id_col) {
                                var beg_label_asym_id = _struct_conf.getColumn('beg_label_asym_id');
                                var beg_label_seq_id = _struct_conf.getColumn('beg_label_seq_id');
                                var pdbx_beg_PDB_ins_code = _struct_conf.getColumn('pdbx_beg_PDB_ins_code');
                                var end_label_asym_id = _struct_conf.getColumn('end_label_asym_id');
                                var end_label_seq_id = _struct_conf.getColumn('end_label_seq_id');
                                var pdbx_end_PDB_ins_code = _struct_conf.getColumn('pdbx_end_PDB_ins_code');
                                var pdbx_PDB_helix_class = _struct_conf.getColumn('pdbx_PDB_helix_class');
                                for (i = 0; i < _struct_conf.rowCount; i++) {
                                    var type = void 0;
                                    switch ((type_id_col.getString(i) || '').toUpperCase()) {
                                        case 'HELX_P':
                                            type = 1 /* Helix */;
                                            break;
                                        case 'TURN_P':
                                            type = 2 /* Turn */;
                                            break;
                                    }
                                    if (!type)
                                        continue;
                                    input[input.length] = new Core.Structure.SecondaryStructureElement(type, residueIdfromColumns(i, beg_label_asym_id, beg_label_seq_id, pdbx_beg_PDB_ins_code), residueIdfromColumns(i, end_label_asym_id, end_label_seq_id, pdbx_end_PDB_ins_code), {
                                        helixClass: pdbx_PDB_helix_class.getString(i)
                                    });
                                }
                            }
                        }
                        if (_struct_sheet_range) {
                            var beg_label_asym_id = _struct_sheet_range.getColumn('beg_label_asym_id');
                            var beg_label_seq_id = _struct_sheet_range.getColumn('beg_label_seq_id');
                            var pdbx_beg_PDB_ins_code = _struct_sheet_range.getColumn('pdbx_beg_PDB_ins_code');
                            var end_label_asym_id = _struct_sheet_range.getColumn('end_label_asym_id');
                            var end_label_seq_id = _struct_sheet_range.getColumn('end_label_seq_id');
                            var pdbx_end_PDB_ins_code = _struct_sheet_range.getColumn('pdbx_end_PDB_ins_code');
                            var symmetry = _struct_sheet_range.getColumn('symmetry');
                            var sheet_id = _struct_sheet_range.getColumn('sheet_id');
                            var id = _struct_sheet_range.getColumn('id');
                            for (i = 0; i < _struct_sheet_range.rowCount; i++) {
                                input[input.length] = new Core.Structure.SecondaryStructureElement(3 /* Sheet */, residueIdfromColumns(i, beg_label_asym_id, beg_label_seq_id, pdbx_beg_PDB_ins_code), residueIdfromColumns(i, end_label_asym_id, end_label_seq_id, pdbx_end_PDB_ins_code), {
                                    symmetry: symmetry.getString(i),
                                    sheetId: sheet_id.getString(i),
                                    id: id.getString(i)
                                });
                            }
                        }
                        var secondary = input.length > 0 ? updateSSIndicesAndFilterEmpty(input, structure) : [];
                        var residues = structure.residues, residueCount = residues.count;
                        if (secondary.length === 0) {
                            analyzeSecondaryStructure(atoms, residues, structure.entities, 0, residueCount, elements);
                            return splitNonconsecutiveSecondaryStructure(residues, elements);
                        }
                        var _max = secondary.length - 1;
                        if (secondary[0].startResidueIndex > 0) {
                            analyzeSecondaryStructure(atoms, residues, structure.entities, 0, secondary[0].startResidueIndex, elements);
                        }
                        for (i = 0; i < _max; i++) {
                            elements[elements.length] = secondary[i];
                            if (secondary[i + 1].startResidueIndex - secondary[i].endResidueIndex > 0) {
                                analyzeSecondaryStructure(atoms, residues, structure.entities, secondary[i].endResidueIndex, secondary[i + 1].startResidueIndex, elements);
                            }
                        }
                        elements[elements.length] = secondary[_max];
                        if (secondary[_max].endResidueIndex < residueCount) {
                            analyzeSecondaryStructure(atoms, residues, structure.entities, secondary[_max].endResidueIndex, residueCount, elements);
                        }
                        return splitNonconsecutiveSecondaryStructure(residues, elements);
                    }
                    function assignSecondaryStructureIndex(residues, ss) {
                        var ssIndex = residues.secondaryStructureIndex;
                        var index = 0;
                        for (var _a = 0, ss_1 = ss; _a < ss_1.length; _a++) {
                            var s = ss_1[_a];
                            for (var i = s.startResidueIndex; i < s.endResidueIndex; i++) {
                                ssIndex[i] = index;
                            }
                            index++;
                        }
                        return ssIndex;
                    }
                    function findResidueIndexByLabel(structure, asymId, seqNumber, insCode) {
                        var _a = structure.chains, _asymId = _a.asymId, residueStartIndex = _a.residueStartIndex, residueEndIndex = _a.residueEndIndex, cCount = _a.count;
                        var _b = structure.residues, _seqNumber = _b.seqNumber, _insCode = _b.insCode;
                        for (var cI = 0; cI < cCount; cI++) {
                            if (_asymId[cI] !== asymId)
                                continue;
                            for (var rI = residueStartIndex[cI], _r = residueEndIndex[cI]; rI < _r; rI++) {
                                if (_seqNumber[rI] === seqNumber && _insCode[rI] === insCode)
                                    return rI;
                            }
                        }
                        return -1;
                    }
                    function findAtomIndexByLabelName(atoms, structure, residueIndex, atomName, altLoc) {
                        var _a = structure.residues, atomStartIndex = _a.atomStartIndex, atomEndIndex = _a.atomEndIndex;
                        var _atomName = atoms.name, _altLoc = atoms.altLoc;
                        for (var i = atomStartIndex[residueIndex], _i = atomEndIndex[residueIndex]; i <= _i; i++) {
                            if (_atomName[i] === atomName && _altLoc[i] === altLoc)
                                return i;
                        }
                        return -1;
                    }
                    function getModRes(data) {
                        var cat = data.getCategory('_pdbx_struct_mod_residue');
                        if (!cat)
                            return void 0;
                        var table = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.ModifiedResidues, cat.rowCount);
                        var label_asym_id = cat.getColumn('label_asym_id');
                        var label_seq_id = cat.getColumn('label_seq_id');
                        var PDB_ins_code = cat.getColumn('PDB_ins_code');
                        var parent_comp_id = cat.getColumn('parent_comp_id');
                        var _details = cat.getColumn('details');
                        var asymId = table.asymId, seqNumber = table.seqNumber, insCode = table.insCode, parent = table.parent, details = table.details;
                        for (var i = 0, __i = cat.rowCount; i < __i; i++) {
                            asymId[i] = label_asym_id.getString(i);
                            seqNumber[i] = label_seq_id.getInteger(i);
                            insCode[i] = PDB_ins_code.getString(i);
                            parent[i] = parent_comp_id.getString(i);
                            details[i] = _details.getString(i);
                        }
                        return table;
                    }
                    function getStructConn(data, atoms, structure) {
                        var cat = data.getCategory('_struct_conn');
                        if (!cat)
                            return void 0;
                        var _idCols = function (i) { return ({
                            label_asym_id: cat.getColumn('ptnr' + i + '_label_asym_id'),
                            label_seq_id: cat.getColumn('ptnr' + i + '_label_seq_id'),
                            label_atom_id: cat.getColumn('ptnr' + i + '_label_atom_id'),
                            label_alt_id: cat.getColumn('pdbx_ptnr' + i + '_label_alt_id'),
                            ins_code: cat.getColumn('pdbx_ptnr' + i + '_PDB_ins_code'),
                            symmetry: cat.getColumn('ptnr' + i + '_symmetry')
                        }); };
                        var conn_type_id = cat.getColumn('conn_type_id');
                        var pdbx_dist_value = cat.getColumn('pdbx_dist_value');
                        var pdbx_value_order = cat.getColumn('pdbx_value_order');
                        var p1 = _idCols(1);
                        var p2 = _idCols(2);
                        var p3 = _idCols(3);
                        var _p = function (row, ps) {
                            if (ps.label_asym_id.getValuePresence(row) !== 0 /* Present */)
                                return void 0;
                            var residueIndex = findResidueIndexByLabel(structure, ps.label_asym_id.getString(row), ps.label_seq_id.getInteger(row), ps.ins_code.getString(row));
                            if (residueIndex < 0)
                                return void 0;
                            var atomIndex = findAtomIndexByLabelName(atoms, structure, residueIndex, ps.label_atom_id.getString(row), ps.label_alt_id.getString(row));
                            if (atomIndex < 0)
                                return void 0;
                            return { residueIndex: residueIndex, atomIndex: atomIndex, symmetry: ps.symmetry.getString(row) || '1_555' };
                        };
                        var _ps = function (row) {
                            var ret = [];
                            var p = _p(row, p1);
                            if (p)
                                ret.push(p);
                            p = _p(row, p2);
                            if (p)
                                ret.push(p);
                            p = _p(row, p3);
                            if (p)
                                ret.push(p);
                            return ret;
                        };
                        var entries = [];
                        for (var i = 0; i < cat.rowCount; i++) {
                            var partners = _ps(i);
                            if (partners.length < 2)
                                continue;
                            var type = conn_type_id.getString(i);
                            var orderType = (pdbx_value_order.getString(i) || '').toLowerCase();
                            var bondType = 0 /* Unknown */;
                            switch (orderType) {
                                case 'sing':
                                    bondType = 1 /* Single */;
                                    break;
                                case 'doub':
                                    bondType = 2 /* Double */;
                                    break;
                                case 'trip':
                                    bondType = 3 /* Triple */;
                                    break;
                                case 'quad':
                                    bondType = 4 /* Aromatic */;
                                    break;
                            }
                            switch (type) {
                                case 'disulf':
                                    bondType = 5 /* DisulfideBridge */;
                                    break;
                                case 'hydrog':
                                    bondType = 8 /* Hydrogen */;
                                    break;
                                case 'metalc':
                                    bondType = 6 /* Metallic */;
                                    break;
                                //case 'mismat': bondType = Structure.BondType.Single; break; 
                                case 'saltbr':
                                    bondType = 7 /* Ion */;
                                    break;
                            }
                            entries.push({
                                bondType: bondType,
                                distance: pdbx_dist_value.getFloat(i),
                                partners: partners
                            });
                        }
                        return new Core.Structure.StructConn(entries);
                    }
                    function parseOperatorList(value) {
                        // '(X0)(1-5)' becomes [['X0']['1', '2', '3', '4', '5']]
                        // kudos to Glen van Ginkel.
                        var oeRegex = /\(?([^\(\)]+)\)?]*/g, g, groups = [], ret = [];
                        while (g = oeRegex.exec(value))
                            groups[groups.length] = g[1];
                        groups.forEach(function (g) {
                            var group = [];
                            g.split(',').forEach(function (e) {
                                var dashIndex = e.indexOf('-');
                                if (dashIndex > 0) {
                                    var from = parseInt(e.substring(0, dashIndex)), to = parseInt(e.substr(dashIndex + 1));
                                    for (var i = from; i <= to; i++)
                                        group[group.length] = i.toString();
                                }
                                else {
                                    group[group.length] = e.trim();
                                }
                            });
                            ret[ret.length] = group;
                        });
                        return ret;
                    }
                    function getAssemblyInfo(data) {
                        var _info = data.getCategory('_pdbx_struct_assembly'), _gen = data.getCategory('_pdbx_struct_assembly_gen'), _opers = data.getCategory('_pdbx_struct_oper_list');
                        if (!_info || !_gen || !_opers) {
                            return void 0;
                        }
                        var i, opers = {}, gens = [], genMap = Core.Utils.FastMap.create();
                        var assembly_id = _gen.getColumn('assembly_id');
                        var oper_expression = _gen.getColumn('oper_expression');
                        var asym_id_list = _gen.getColumn('asym_id_list');
                        for (i = 0; i < _gen.rowCount; i++) {
                            var id = assembly_id.getString(i);
                            if (!id) {
                                return void 0;
                            }
                            var entry = genMap.get(id);
                            if (!entry) {
                                entry = new Core.Structure.AssemblyGen(id);
                                genMap.set(id, entry);
                                gens.push(entry);
                            }
                            entry.gens.push(new Core.Structure.AssemblyGenEntry(parseOperatorList(oper_expression.getString(i)), asym_id_list.getString(i).split(',')));
                        }
                        var _pdbx_struct_oper_list_id = _opers.getColumn('id');
                        var _pdbx_struct_oper_list_name = _opers.getColumn('name');
                        for (i = 0; i < _opers.rowCount; i++) {
                            var oper = getTransform(_opers, 'matrix', 'vector', i);
                            if (!oper) {
                                return void 0;
                            }
                            var op = new Core.Structure.AssemblyOperator(_pdbx_struct_oper_list_id.getString(i), _pdbx_struct_oper_list_name.getString(i), oper);
                            opers[op.id] = op;
                        }
                        return new Core.Structure.AssemblyInfo(opers, gens);
                    }
                    function getSymmetryInfo(data) {
                        var _cell = data.getCategory('_cell'), _symmetry = data.getCategory('_symmetry'), _atom_sites = data.getCategory('_atom_sites');
                        var spacegroupName = '', cellSize = [1.0, 1.0, 1.0], cellAngles = [90.0, 90.0, 90.0], toFracTransform = Core.Geometry.LinearAlgebra.Matrix4.identity(), isNonStandardCrytalFrame = false;
                        if (!_cell || !_symmetry) {
                            return void 0;
                        }
                        spacegroupName = _symmetry.getColumn('space_group_name_H-M').getString(0);
                        cellSize = [_cell.getColumn('length_a').getFloat(0), _cell.getColumn('length_b').getFloat(0), _cell.getColumn('length_c').getFloat(0)];
                        cellAngles = [_cell.getColumn('angle_alpha').getFloat(0), _cell.getColumn('angle_beta').getFloat(0), _cell.getColumn('angle_gamma').getFloat(0)];
                        if (!spacegroupName || cellSize.every(function (s) { return isNaN(s) || s === 0.0; }) || cellSize.every(function (s) { return isNaN(s) || s === 0.0; })) {
                            return void 0;
                        }
                        var sq = function (x) { return x * x; };
                        var toRadians = function (degs) { return degs * Math.PI / 180.0; };
                        var la = cellSize[0], lb = cellSize[1], lc = cellSize[2], aa = toRadians(cellAngles[0]), ab = toRadians(cellAngles[1]), ac = toRadians(cellAngles[2]), v = la * lb * lc * Math.sqrt(1.0 - sq(Math.cos(aa)) - sq(Math.cos(ab)) - sq(Math.cos(ac)) + 2.0 * Math.cos(aa) * Math.cos(ab) * Math.cos(ac));
                        var fromFrac = Core.Geometry.LinearAlgebra.Matrix4.ofRows([
                            [la, lb * Math.cos(ac), lc * Math.cos(ab), 0.0],
                            [0.0, lb * Math.sin(ac), lc * (Math.cos(aa) - Math.cos(ab) * Math.cos(ac)) / Math.sin(ac), 0.0],
                            [0.0, 0.0, v / (la * lb * Math.sin(ac)), 0.0],
                            [0.0, 0.0, 0.0, 1.0]
                        ]);
                        var toFracComputed = Core.Geometry.LinearAlgebra.Matrix4.identity();
                        Core.Geometry.LinearAlgebra.Matrix4.invert(toFracComputed, fromFrac);
                        if (_atom_sites) {
                            var transform = getTransform(_atom_sites, 'fract_transf_matrix', 'fract_transf_vector', 0);
                            if (transform) {
                                toFracTransform = transform;
                                if (!Core.Geometry.LinearAlgebra.Matrix4.areEqual(toFracComputed, transform, 0.0001)) {
                                    isNonStandardCrytalFrame = true;
                                }
                            }
                        }
                        else {
                            toFracTransform = toFracComputed;
                        }
                        return new Core.Structure.SymmetryInfo(spacegroupName, cellSize, cellAngles, toFracTransform, isNonStandardCrytalFrame);
                    }
                    function getComponentBonds(category) {
                        if (!category || !category.rowCount)
                            return void 0;
                        var info = new Core.Structure.ComponentBondInfo();
                        var idCol = category.getColumn('comp_id'), nameACol = category.getColumn('atom_id_1'), nameBCol = category.getColumn('atom_id_2'), orderCol = category.getColumn('value_order'), count = category.rowCount;
                        var entry = info.newEntry(idCol.getString(0));
                        for (var i = 0; i < count; i++) {
                            var id = idCol.getString(i), nameA = nameACol.getString(i), nameB = nameBCol.getString(i), order = orderCol.getString(i);
                            if (entry.id !== id) {
                                entry = info.newEntry(id);
                            }
                            var t = void 0;
                            switch (order.toLowerCase()) {
                                case 'sing':
                                    t = 1 /* Single */;
                                    break;
                                case 'doub':
                                case 'delo':
                                    t = 2 /* Double */;
                                    break;
                                case 'trip':
                                    t = 3 /* Triple */;
                                    break;
                                case 'quad':
                                    t = 4 /* Aromatic */;
                                    break;
                                default:
                                    t = 0 /* Unknown */;
                                    break;
                            }
                            entry.add(nameA, nameB, t);
                        }
                        return info;
                    }
                    function getModel(startRow, data, atomSiteColumns) {
                        var _a = buildModelAtomTable(startRow, data.getCategory('_atom_site').rowCount, atomSiteColumns), atoms = _a.atoms, positions = _a.positions, modelId = _a.modelId, endRow = _a.endRow, structure = buildStructure(atomSiteColumns, atoms), entry = data.getCategory('_entry'), id;
                        if (entry && entry.getColumn('id').isDefined)
                            id = entry.getColumn('id').getString(0);
                        else
                            id = data.header;
                        assignEntityTypes(data.getCategory('_entity'), structure.entities);
                        var ss = getSecondaryStructureInfo(data, atoms, structure);
                        assignSecondaryStructureIndex(structure.residues, ss);
                        return {
                            model: Core.Structure.Molecule.Model.create({
                                id: id,
                                modelId: modelId,
                                data: {
                                    atoms: atoms,
                                    residues: structure.residues,
                                    chains: structure.chains,
                                    entities: structure.entities,
                                    bonds: {
                                        structConn: getStructConn(data, atoms, structure),
                                        component: getComponentBonds(data.getCategory('_chem_comp_bond'))
                                    },
                                    modifiedResidues: getModRes(data),
                                    secondaryStructure: ss,
                                    symmetryInfo: getSymmetryInfo(data),
                                    assemblyInfo: getAssemblyInfo(data),
                                },
                                positions: positions,
                                source: Core.Structure.Molecule.Model.Source.File
                            }),
                            endRow: endRow
                        };
                    }
                    function ofDataBlock(data) {
                        var models = [], atomSite = data.getCategory('_atom_site'), startRow = 0;
                        if (!atomSite) {
                            throw "'_atom_site' category is missing in the input.";
                        }
                        var entry = data.getCategory('_entry'), atomColumns = getAtomSiteColumns(atomSite), id;
                        if (entry && entry.getColumn('id').isDefined)
                            id = entry.getColumn('id').getString(0);
                        else
                            id = data.header;
                        while (startRow < atomSite.rowCount) {
                            var _a = getModel(startRow, data, atomColumns), model = _a.model, endRow = _a.endRow;
                            models.push(model);
                            startRow = endRow;
                        }
                        var experimentMethods = void 0;
                        var _exptl = data.getCategory('_exptl');
                        if (_exptl) {
                            experimentMethods = [];
                            var method = _exptl.getColumn('method');
                            for (var i = 0; i < _exptl.rowCount; i++) {
                                if (method.getValuePresence(i) !== 0 /* Present */)
                                    continue;
                                experimentMethods.push(method.getString(i));
                            }
                        }
                        return Core.Structure.Molecule.create(id, models, { experimentMethods: experimentMethods });
                    }
                    mmCIF.ofDataBlock = ofDataBlock;
                })(mmCIF = Molecule.mmCIF || (Molecule.mmCIF = {}));
            })(Molecule = Formats.Molecule || (Formats.Molecule = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Molecule;
            (function (Molecule) {
                var PDB;
                (function (PDB) {
                    "use strict";
                    var MoleculeData = /** @class */ (function () {
                        function MoleculeData(header, crystInfo, models, data) {
                            this.header = header;
                            this.crystInfo = crystInfo;
                            this.models = models;
                            this.data = data;
                        }
                        MoleculeData.prototype.makeEntities = function () {
                            var data = [
                                "data_ent",
                                "loop_",
                                "_entity.id",
                                "_entity.type",
                                "_entity.src_method",
                                "_entity.pdbx_description",
                                "_entity.formula_weight",
                                "_entity.pdbx_number_of_molecules",
                                "_entity.details",
                                "_entity.pdbx_mutation",
                                "_entity.pdbx_fragment",
                                "_entity.pdbx_ec",
                                "1 polymer man polymer 0.0 0 ? ? ? ?",
                                "2 non-polymer syn non-polymer 0.0 0 ? ? ? ?",
                                "3 water nat water 0.0 0 ? ? ? ?"
                            ].join('\n');
                            var file = Formats.CIF.Text.parse(data);
                            if (file.isError) {
                                throw file.toString();
                            }
                            return file.result.dataBlocks[0].getCategory('_entity');
                        };
                        MoleculeData.prototype.toCifFile = function () {
                            var helpers = {
                                dot: PDB.Parser.getDotRange(this.data.length),
                                question: PDB.Parser.getQuestionmarkRange(this.data.length),
                                numberTokens: PDB.Parser.getNumberRanges(this.data.length),
                                data: this.data
                            };
                            var file = new Formats.CIF.Text.File(this.data);
                            var block = new Formats.CIF.Text.DataBlock(this.data, this.header.id);
                            file.dataBlocks.push(block);
                            block.addCategory(this.makeEntities());
                            if (this.crystInfo) {
                                var _a = this.crystInfo.toCifCategory(this.header.id), cell = _a.cell, symm = _a.symm;
                                block.addCategory(cell);
                                block.addCategory(symm);
                            }
                            block.addCategory(this.models.toCifCategory(block, helpers));
                            return file;
                        };
                        return MoleculeData;
                    }());
                    PDB.MoleculeData = MoleculeData;
                    var Header = /** @class */ (function () {
                        function Header(id) {
                            this.id = id;
                        }
                        return Header;
                    }());
                    PDB.Header = Header;
                    var CrystStructureInfo = /** @class */ (function () {
                        function CrystStructureInfo(record) {
                            this.record = record;
                        }
                        CrystStructureInfo.prototype.getValue = function (start, len) {
                            var ret = this.record.substr(6, 9).trim();
                            if (!ret.length)
                                return '.';
                            return ret;
                        };
                        CrystStructureInfo.prototype.toCifCategory = function (id) {
                            //COLUMNS       DATA TYPE      CONTENTS
                            //--------------------------------------------------------------------------------
                            //    1 - 6       Record name    "CRYST1"
                            //7 - 15       Real(9.3)      a (Angstroms)
                            //16 - 24       Real(9.3)      b (Angstroms)
                            //25 - 33       Real(9.3)      c (Angstroms)
                            //34 - 40       Real(7.2)      alpha (degrees)
                            //41 - 47       Real(7.2)      beta (degrees)
                            //48 - 54       Real(7.2)      gamma (degrees)
                            //56 - 66       LString        Space group       
                            //67 - 70       Integer        Z value           
                            var data = [
                                "_cell.entry_id           '" + id + "'",
                                "_cell.length_a           " + this.getValue(6, 9),
                                "_cell.length_b           " + this.getValue(15, 9),
                                "_cell.length_c           " + this.getValue(24, 9),
                                "_cell.angle_alpha        " + this.getValue(33, 7),
                                "_cell.angle_beta         " + this.getValue(40, 7),
                                "_cell.angle_gamma        " + this.getValue(48, 7),
                                "_cell.Z_PDB              " + this.getValue(66, 4),
                                "_cell.pdbx_unique_axis   ?",
                                "_symmetry.entry_id                         '" + id + "'",
                                "_symmetry.space_group_name_H-M             '" + this.getValue(55, 11) + "'",
                                "_symmetry.pdbx_full_space_group_name_H-M   ?",
                                "_symmetry.cell_setting                     ?",
                                "_symmetry.Int_Tables_number                ?",
                                "_symmetry.space_group_name_Hall            ?"
                            ].join('\n');
                            var cif = Formats.CIF.Text.parse(data);
                            if (cif.isError) {
                                throw new Error(cif.toString());
                            }
                            return {
                                cell: cif.result.dataBlocks[0].getCategory('_cell'),
                                symm: cif.result.dataBlocks[0].getCategory('_symmetry')
                            };
                        };
                        return CrystStructureInfo;
                    }());
                    PDB.CrystStructureInfo = CrystStructureInfo;
                    var SecondaryStructure = /** @class */ (function () {
                        function SecondaryStructure(helixTokens, sheetTokens) {
                            this.helixTokens = helixTokens;
                            this.sheetTokens = sheetTokens;
                        }
                        SecondaryStructure.prototype.toCifCategory = function (data) {
                            return void 0;
                        };
                        return SecondaryStructure;
                    }());
                    PDB.SecondaryStructure = SecondaryStructure;
                    var ModelData = /** @class */ (function () {
                        function ModelData(idToken, atomTokens, atomCount) {
                            this.idToken = idToken;
                            this.atomTokens = atomTokens;
                            this.atomCount = atomCount;
                        }
                        ModelData.prototype.writeToken = function (index, cifTokens) {
                            Core.Utils.ArrayBuilder.add2(cifTokens, this.atomTokens[2 * index], this.atomTokens[2 * index + 1]);
                        };
                        ModelData.prototype.writeTokenCond = function (index, cifTokens, dot) {
                            var s = this.atomTokens[2 * index];
                            var e = this.atomTokens[2 * index + 1];
                            if (s === e)
                                Core.Utils.ArrayBuilder.add2(cifTokens, dot.start, dot.end);
                            else
                                Core.Utils.ArrayBuilder.add2(cifTokens, s, e);
                        };
                        ModelData.prototype.writeRange = function (range, cifTokens) {
                            Core.Utils.ArrayBuilder.add2(cifTokens, range.start, range.end);
                        };
                        ModelData.prototype.tokenEquals = function (start, end, value, data) {
                            var len = value.length;
                            if (len !== end - start)
                                return false;
                            for (var i = value.length - 1; i >= 0; i--) {
                                if (data.charCodeAt(i + start) !== value.charCodeAt(i)) {
                                    return false;
                                }
                            }
                            return true;
                        };
                        ModelData.prototype.getEntityType = function (row, data) {
                            var o = row * 14;
                            if (this.tokenEquals(this.atomTokens[2 * o], this.atomTokens[2 * o + 1], "HETATM", data)) {
                                var s = this.atomTokens[2 * (o + 4)], e = this.atomTokens[2 * (o + 4) + 1];
                                if (this.tokenEquals(s, e, "HOH", data) || this.tokenEquals(s, e, "WTR", data) || this.tokenEquals(s, e, "SOL", data)) {
                                    return 3; // water
                                }
                                return 2; // non-polymer
                            }
                            else {
                                return 1; // polymer
                            }
                        };
                        ModelData.prototype.writeCifTokens = function (modelToken, cifTokens, helpers) {
                            var columnIndices = {
                                //COLUMNS        DATA TYPE       CONTENTS                            
                                //--------------------------------------------------------------------------------
                                // 1 -  6        Record name     "ATOM  "                                          
                                RECORD: 0,
                                // 7 - 11        Integer         Atom serial number.                   
                                SERIAL: 1,
                                //13 - 16        Atom            Atom name.          
                                ATOM_NAME: 2,
                                //17             Character       Alternate location indicator. 
                                ALT_LOC: 3,
                                //18 - 20        Residue name    Residue name.       
                                RES_NAME: 4,
                                //22             Character       Chain identifier.         
                                CHAIN_ID: 5,
                                //23 - 26        Integer         Residue sequence number.              
                                RES_SEQN: 6,
                                //27             AChar           Code for insertion of residues.       
                                INS_CODE: 7,
                                //31 - 38        Real(8.3)       Orthogonal coordinates for X in Angstroms.   
                                X: 8,
                                //39 - 46        Real(8.3)       Orthogonal coordinates for Y in Angstroms.                            
                                Y: 9,
                                //47 - 54        Real(8.3)       Orthogonal coordinates for Z in Angstroms.        
                                Z: 10,
                                //55 - 60        Real(6.2)       Occupancy.       
                                OCCUPANCY: 11,
                                //61 - 66        Real(6.2)       Temperature factor (Default = 0.0).                   
                                TEMP_FACTOR: 12,
                                //73 - 76        LString(4)      Segment identifier, left-justified.   
                                // ignored
                                //77 - 78        LString(2)      Element symbol, right-justified.   
                                ELEMENT: 13
                                //79 - 80        LString(2)      Charge on the atom.      
                                // ignored
                            };
                            var columnCount = 14;
                            for (var i = 0; i < this.atomCount; i++) {
                                var o = i * columnCount;
                                //_atom_site.group_PDB
                                this.writeToken(o + columnIndices.RECORD, cifTokens);
                                //_atom_site.id
                                this.writeToken(o + columnIndices.SERIAL, cifTokens);
                                //_atom_site.type_symbol
                                this.writeToken(o + columnIndices.ELEMENT, cifTokens);
                                //_atom_site.label_atom_id
                                this.writeToken(o + columnIndices.ATOM_NAME, cifTokens);
                                //_atom_site.label_alt_id
                                this.writeTokenCond(o + columnIndices.ALT_LOC, cifTokens, helpers.dot);
                                //_atom_site.label_comp_id
                                this.writeToken(o + columnIndices.RES_NAME, cifTokens);
                                //_atom_site.label_asym_id
                                this.writeToken(o + columnIndices.CHAIN_ID, cifTokens);
                                //_atom_site.label_entity_id
                                this.writeRange(helpers.numberTokens.get(this.getEntityType(i, helpers.data)), cifTokens);
                                //_atom_site.label_seq_id
                                this.writeToken(o + columnIndices.RES_SEQN, cifTokens);
                                //_atom_site.pdbx_PDB_ins_code
                                this.writeTokenCond(o + columnIndices.INS_CODE, cifTokens, helpers.dot);
                                //_atom_site.Cartn_x
                                this.writeToken(o + columnIndices.X, cifTokens);
                                //_atom_site.Cartn_y
                                this.writeToken(o + columnIndices.Y, cifTokens);
                                //_atom_site.Cartn_z
                                this.writeToken(o + columnIndices.Z, cifTokens);
                                //_atom_site.occupancy
                                this.writeToken(o + columnIndices.OCCUPANCY, cifTokens);
                                //_atom_site.B_iso_or_equiv
                                this.writeToken(o + columnIndices.TEMP_FACTOR, cifTokens);
                                //_atom_site.Cartn_x_esd
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.Cartn_y_esd
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.Cartn_z_esd
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.occupancy_esd
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.B_iso_or_equiv_esd
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.pdbx_formal_charge
                                this.writeRange(helpers.question, cifTokens);
                                //_atom_site.auth_seq_id
                                this.writeToken(o + columnIndices.RES_SEQN, cifTokens);
                                //_atom_site.auth_comp_id
                                this.writeToken(o + columnIndices.RES_NAME, cifTokens);
                                //_atom_site.auth_asym_id
                                this.writeToken(o + columnIndices.CHAIN_ID, cifTokens);
                                //_atom_site.auth_atom_id
                                this.writeToken(o + columnIndices.ATOM_NAME, cifTokens);
                                //_atom_site.pdbx_PDB_model_num 
                                this.writeRange(modelToken, cifTokens);
                            }
                        };
                        ModelData.COLUMNS = [
                            "_atom_site.group_PDB",
                            "_atom_site.id",
                            "_atom_site.type_symbol",
                            "_atom_site.label_atom_id",
                            "_atom_site.label_alt_id",
                            "_atom_site.label_comp_id",
                            "_atom_site.label_asym_id",
                            "_atom_site.label_entity_id",
                            "_atom_site.label_seq_id",
                            "_atom_site.pdbx_PDB_ins_code",
                            "_atom_site.Cartn_x",
                            "_atom_site.Cartn_y",
                            "_atom_site.Cartn_z",
                            "_atom_site.occupancy",
                            "_atom_site.B_iso_or_equiv",
                            "_atom_site.Cartn_x_esd",
                            "_atom_site.Cartn_y_esd",
                            "_atom_site.Cartn_z_esd",
                            "_atom_site.occupancy_esd",
                            "_atom_site.B_iso_or_equiv_esd",
                            "_atom_site.pdbx_formal_charge",
                            "_atom_site.auth_seq_id",
                            "_atom_site.auth_comp_id",
                            "_atom_site.auth_asym_id",
                            "_atom_site.auth_atom_id",
                            "_atom_site.pdbx_PDB_model_num"
                        ];
                        return ModelData;
                    }());
                    PDB.ModelData = ModelData;
                    var ModelsData = /** @class */ (function () {
                        function ModelsData(models) {
                            this.models = models;
                        }
                        ModelsData.prototype.toCifCategory = function (block, helpers) {
                            var atomCount = 0;
                            for (var _i = 0, _a = this.models; _i < _a.length; _i++) {
                                var m = _a[_i];
                                atomCount += m.atomCount;
                            }
                            var colCount = 26;
                            var tokens = Core.Utils.ArrayBuilder.forTokenIndices(atomCount * colCount);
                            for (var _b = 0, _c = this.models; _b < _c.length; _b++) {
                                var m = _c[_b];
                                m.writeCifTokens(m.idToken, tokens, helpers);
                            }
                            return new Formats.CIF.Text.Category(block.data, "_atom_site", 0, 0, ModelData.COLUMNS, tokens.array, atomCount * colCount);
                        };
                        return ModelsData;
                    }());
                    PDB.ModelsData = ModelsData;
                })(PDB = Molecule.PDB || (Molecule.PDB = {}));
            })(Molecule = Formats.Molecule || (Formats.Molecule = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Molecule;
            (function (Molecule) {
                var PDB;
                (function (PDB) {
                    "use strict";
                    var Tokenizer = /** @class */ (function () {
                        function Tokenizer(data) {
                            this.data = data;
                            this.trimmedToken = { start: 0, end: 0 };
                            this.line = 0;
                            this.position = 0;
                            this.length = data.length;
                        }
                        Tokenizer.prototype.moveToNextLine = function () {
                            while (this.position < this.length && this.data.charCodeAt(this.position) !== 10) {
                                this.position++;
                            }
                            this.position++;
                            this.line++;
                            return this.position;
                        };
                        Tokenizer.prototype.moveToEndOfLine = function () {
                            while (this.position < this.length) {
                                var c = this.data.charCodeAt(this.position);
                                if (c === 10 || c === 13) { //  /n | /r
                                    return this.position;
                                }
                                this.position++;
                            }
                            return this.position;
                        };
                        Tokenizer.prototype.startsWith = function (start, value) {
                            for (var i = value.length - 1; i >= 0; i--) {
                                if (this.data.charCodeAt(i + start) !== value.charCodeAt(i)) {
                                    return false;
                                }
                            }
                            return true;
                        };
                        Tokenizer.prototype.trim = function (start, end) {
                            while (start < end && this.data.charCodeAt(start) === 32)
                                start++;
                            while (end > start && this.data.charCodeAt(end - 1) === 32)
                                end--;
                            this.trimmedToken.start = start;
                            this.trimmedToken.end = end;
                        };
                        Tokenizer.prototype.tokenizeAtomRecord = function (tokens) {
                            var startPos = this.position;
                            var start = this.position;
                            var end = this.moveToEndOfLine();
                            var length = end - start;
                            // invalid atom record
                            if (length < 60)
                                return false;
                            //COLUMNS        DATA TYPE       CONTENTS                            
                            //--------------------------------------------------------------------------------
                            // 1 -  6        Record name     "ATOM  "                                            
                            this.trim(start, start + 6);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            // 7 - 11        Integer         Atom serial number.                   
                            start = startPos + 6;
                            this.trim(start, start + 5);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //13 - 16        Atom            Atom name.          
                            start = startPos + 12;
                            this.trim(start, start + 4);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //17             Character       Alternate location indicator. 
                            if (this.data.charCodeAt(startPos + 16) === 32) { // ' '
                                Formats.TokenIndexBuilder.addToken(tokens, 0, 0);
                            }
                            else {
                                Formats.TokenIndexBuilder.addToken(tokens, startPos + 16, startPos + 17);
                            }
                            //18 - 20        Residue name    Residue name.       
                            start = startPos + 17;
                            this.trim(start, start + 3);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //22             Character       Chain identifier.         
                            Formats.TokenIndexBuilder.addToken(tokens, startPos + 21, startPos + 22);
                            //23 - 26        Integer         Residue sequence number.              
                            start = startPos + 22;
                            this.trim(start, start + 4);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //27             AChar           Code for insertion of residues.      
                            if (this.data.charCodeAt(startPos + 26) === 32) { // ' '
                                Formats.TokenIndexBuilder.addToken(tokens, 0, 0);
                            }
                            else {
                                Formats.TokenIndexBuilder.addToken(tokens, startPos + 26, startPos + 27);
                            }
                            //31 - 38        Real(8.3)       Orthogonal coordinates for X in Angstroms.   
                            start = startPos + 30;
                            this.trim(start, start + 8);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //39 - 46        Real(8.3)       Orthogonal coordinates for Y in Angstroms.                            
                            start = startPos + 38;
                            this.trim(start, start + 8);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //47 - 54        Real(8.3)       Orthogonal coordinates for Z in Angstroms.        
                            start = startPos + 46;
                            this.trim(start, start + 8);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //55 - 60        Real(6.2)       Occupancy.       
                            start = startPos + 54;
                            this.trim(start, start + 6);
                            Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            //61 - 66        Real(6.2)       Temperature factor (Default = 0.0).                   
                            if (length >= 66) {
                                start = startPos + 60;
                                this.trim(start, start + 6);
                                Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                            }
                            else {
                                Formats.TokenIndexBuilder.addToken(tokens, 0, 0);
                            }
                            //73 - 76        LString(4)      Segment identifier, left-justified.   
                            // ignored
                            //77 - 78        LString(2)      Element symbol, right-justified.   
                            if (length >= 78) {
                                start = startPos + 76;
                                this.trim(start, start + 2);
                                if (this.trimmedToken.start < this.trimmedToken.end) {
                                    Formats.TokenIndexBuilder.addToken(tokens, this.trimmedToken.start, this.trimmedToken.end);
                                }
                                else {
                                    Formats.TokenIndexBuilder.addToken(tokens, startPos + 12, startPos + 13);
                                }
                            }
                            else {
                                Formats.TokenIndexBuilder.addToken(tokens, startPos + 12, startPos + 13);
                            }
                            //79 - 80        LString(2)      Charge on the atom.      
                            // ignored
                            return true;
                        };
                        return Tokenizer;
                    }());
                    var Parser = /** @class */ (function () {
                        function Parser() {
                        }
                        Parser.tokenizeAtom = function (tokens, tokenizer) {
                            if (tokenizer.tokenizeAtomRecord(tokens)) {
                                return void 0;
                            }
                            return new Formats.ParserError("Invalid ATOM/HETATM record.", tokenizer.line);
                        };
                        Parser.tokenize = function (id, data) {
                            var tokenizer = new Tokenizer(data);
                            var length = data.length;
                            var modelAtomTokens = Formats.TokenIndexBuilder.create(4096); //2 * 14 * this.data.length / 78);
                            var atomCount = 0;
                            var models = [];
                            var cryst = void 0;
                            var modelIdToken = { start: 0, end: 0 };
                            while (tokenizer.position < length) {
                                var cont = true;
                                switch (data.charCodeAt(tokenizer.position)) {
                                    case 65: // A 
                                        if (tokenizer.startsWith(tokenizer.position, "ATOM")) {
                                            if (!modelAtomTokens) {
                                                modelAtomTokens = Formats.TokenIndexBuilder.create(4096);
                                            }
                                            var err = Parser.tokenizeAtom(modelAtomTokens, tokenizer);
                                            atomCount++;
                                            if (err)
                                                return err;
                                        }
                                        break;
                                    case 67: // C
                                        if (tokenizer.startsWith(tokenizer.position, "CRYST1")) {
                                            var start = tokenizer.position;
                                            var end = tokenizer.moveToEndOfLine();
                                            cryst = new PDB.CrystStructureInfo(data.substring(start, end));
                                        }
                                        break;
                                    case 69: // E 
                                        if (tokenizer.startsWith(tokenizer.position, "ENDMDL") && atomCount > 0) {
                                            if (models.length === 0) {
                                                modelIdToken = { start: data.length + 3, end: data.length + 4 };
                                            }
                                            if (modelAtomTokens) {
                                                models.push(new PDB.ModelData(modelIdToken, modelAtomTokens.tokens, atomCount));
                                            }
                                            atomCount = 0;
                                            modelAtomTokens = null;
                                        }
                                        else if (tokenizer.startsWith(tokenizer.position, "END")) {
                                            var start = tokenizer.position;
                                            var end = tokenizer.moveToEndOfLine();
                                            tokenizer.trim(start, end);
                                            if (tokenizer.trimmedToken.end - tokenizer.trimmedToken.start === 3) {
                                                cont = false;
                                            }
                                        }
                                        break;
                                    case 72: // H 
                                        if (tokenizer.startsWith(tokenizer.position, "HETATM")) {
                                            if (!modelAtomTokens) {
                                                modelAtomTokens = Formats.TokenIndexBuilder.create(4096);
                                            }
                                            var err = Parser.tokenizeAtom(modelAtomTokens, tokenizer);
                                            atomCount++;
                                            if (err)
                                                return err;
                                        }
                                        break;
                                    case 77: //M
                                        if (tokenizer.startsWith(tokenizer.position, "MODEL")) {
                                            if (atomCount > 0) {
                                                if (models.length === 0) {
                                                    modelIdToken = { start: data.length + 3, end: data.length + 4 };
                                                }
                                                if (modelAtomTokens) {
                                                    models.push(new PDB.ModelData(modelIdToken, modelAtomTokens.tokens, atomCount));
                                                }
                                            }
                                            var start = tokenizer.position + 6;
                                            var end = tokenizer.moveToEndOfLine();
                                            tokenizer.trim(start, end);
                                            modelIdToken = { start: tokenizer.trimmedToken.start, end: tokenizer.trimmedToken.end };
                                            if (atomCount > 0 || !modelAtomTokens) {
                                                modelAtomTokens = Formats.TokenIndexBuilder.create(4096);
                                            }
                                            atomCount = 0;
                                        }
                                        break;
                                }
                                tokenizer.moveToNextLine();
                                if (!cont)
                                    break;
                            }
                            var fakeCifData = data + ".?0123";
                            if (atomCount > 0) {
                                if (models.length === 0) {
                                    modelIdToken = { start: data.length + 3, end: data.length + 4 };
                                }
                                if (modelAtomTokens) {
                                    models.push(new PDB.ModelData(modelIdToken, modelAtomTokens.tokens, atomCount));
                                }
                            }
                            return new PDB.MoleculeData(new PDB.Header(id), cryst, new PDB.ModelsData(models), fakeCifData);
                        };
                        Parser.getDotRange = function (length) {
                            return { start: length - 6, end: length - 5 };
                        };
                        Parser.getNumberRanges = function (length) {
                            var ret = Core.Utils.FastMap.create();
                            for (var i = 0; i < 4; i++) {
                                ret.set(i, { start: length - 4 + i, end: length - 3 + i });
                            }
                            return ret;
                        };
                        Parser.getQuestionmarkRange = function (length) {
                            return { start: length - 5, end: length - 4 };
                        };
                        Parser.parse = function (id, data) {
                            var ret = Parser.tokenize(id, data);
                            if (ret instanceof Formats.ParserError) {
                                return Formats.ParserResult.error(ret.message, ret.line);
                            }
                            else {
                                return Formats.ParserResult.success(ret.toCifFile());
                            }
                        };
                        return Parser;
                    }());
                    PDB.Parser = Parser;
                    function toCifFile(id, data) {
                        return Parser.parse(id, data);
                    }
                    PDB.toCifFile = toCifFile;
                })(PDB = Molecule.PDB || (Molecule.PDB = {}));
            })(Molecule = Formats.Molecule || (Formats.Molecule = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Molecule;
            (function (Molecule) {
                var SDF;
                (function (SDF) {
                    function initState(data, customId) {
                        var lines = data.split(/\r?\n/g);
                        var id = lines[0].trim();
                        if (!id.length)
                            id = 'SDF';
                        //let molHeaderInfo = lines[1];
                        //let molHeaderComment = lines[2];
                        var cTabInfo = lines[3];
                        var atomCount = +cTabInfo.substr(0, 3);
                        var bondCount = +cTabInfo.substr(3, 3);
                        return {
                            id: customId ? customId : id,
                            atomCount: atomCount,
                            bondCount: bondCount,
                            atoms: Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Atoms, atomCount),
                            positions: Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Positions, atomCount),
                            bonds: Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Bonds, bondCount),
                            lines: lines,
                            currentLine: 4,
                            error: void 0,
                            stringPool: Formats.ShortStringPool.create()
                        };
                    }
                    function readAtom(i, state) {
                        var line = state.lines[state.currentLine];
                        var atoms = state.atoms, positions = state.positions;
                        var es = Formats.ShortStringPool.get(state.stringPool, line.substr(31, 3).trim());
                        atoms.id[i] = i;
                        atoms.elementSymbol[i] = es;
                        atoms.name[i] = es;
                        atoms.authName[i] = es;
                        atoms.occupancy[i] = 1.0;
                        atoms.rowIndex[i] = state.currentLine;
                        positions.x[i] = Core.Utils.FastNumberParsers.parseFloatSkipTrailingWhitespace(line, 0, 10);
                        positions.y[i] = Core.Utils.FastNumberParsers.parseFloatSkipTrailingWhitespace(line, 10, 20);
                        positions.z[i] = Core.Utils.FastNumberParsers.parseFloatSkipTrailingWhitespace(line, 20, 30);
                    }
                    function readAtoms(state) {
                        for (var i = 0; i < state.atomCount; i++) {
                            readAtom(i, state);
                            state.currentLine++;
                        }
                    }
                    function readBond(i, state) {
                        var line = state.lines[state.currentLine];
                        var bonds = state.bonds;
                        bonds.atomAIndex[i] = Core.Utils.FastNumberParsers.parseIntSkipTrailingWhitespace(line, 0, 3) - 1;
                        bonds.atomBIndex[i] = Core.Utils.FastNumberParsers.parseIntSkipTrailingWhitespace(line, 3, 6) - 1;
                        switch (Core.Utils.FastNumberParsers.parseIntSkipTrailingWhitespace(line, 6, 9)) {
                            case 1:
                                bonds.type[i] = 1 /* Single */;
                                break;
                            case 2:
                                bonds.type[i] = 2 /* Double */;
                                break;
                            case 3:
                                bonds.type[i] = 3 /* Triple */;
                                break;
                            case 4:
                                bonds.type[i] = 4 /* Aromatic */;
                                break;
                            default:
                                bonds.type[i] = 0 /* Unknown */;
                                break;
                        }
                    }
                    function readBonds(state) {
                        for (var i = 0; i < state.bondCount; i++) {
                            readBond(i, state);
                            state.currentLine++;
                        }
                    }
                    function buildModel(state) {
                        var residues = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Residues, 1), chains = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Chains, 1), entities = Core.Utils.DataTable.ofDefinition(Core.Structure.Tables.Entities, 1);
                        residues.isHet[0] = 1;
                        residues.insCode[0] = null;
                        residues.name[0]
                            = residues.authName[0]
                                = 'UNK';
                        residues.atomEndIndex[0]
                            = chains.atomEndIndex[0]
                                = entities.atomEndIndex[0]
                                    = state.atomCount;
                        residues.asymId[0]
                            = residues.authAsymId[0]
                                = chains.asymId[0]
                                    = chains.authAsymId[0]
                                        = 'X';
                        residues.entityId[0]
                            = chains.entityId[0]
                                = entities.entityId[0]
                                    = '1';
                        chains.residueEndIndex[0]
                            = entities.residueEndIndex[0]
                                = 0;
                        entities.chainEndIndex[0] = 1;
                        entities.type[0] = 'non-polymer';
                        var ssR = new Core.Structure.PolyResidueIdentifier('X', 0, null);
                        var ss = [new Core.Structure.SecondaryStructureElement(0 /* None */, ssR, ssR)];
                        ss[0].startResidueIndex = 0;
                        ss[0].endResidueIndex = 1;
                        return Core.Structure.Molecule.Model.create({
                            id: state.id,
                            modelId: '1',
                            data: {
                                atoms: state.atoms,
                                residues: residues,
                                chains: chains,
                                entities: entities,
                                bonds: {
                                    input: state.bonds,
                                },
                                secondaryStructure: ss,
                                symmetryInfo: void 0,
                                assemblyInfo: void 0,
                            },
                            positions: state.positions,
                            source: Core.Structure.Molecule.Model.Source.File
                        });
                    }
                    function parse(data, id) {
                        try {
                            var state = initState(data, id);
                            readAtoms(state);
                            readBonds(state);
                            var model = buildModel(state);
                            if (state.error) {
                                return Formats.ParserResult.error(state.error, state.currentLine + 1);
                            }
                            var molecule = Core.Structure.Molecule.create(id ? id : state.id, [model]);
                            return Formats.ParserResult.success(molecule);
                        }
                        catch (e) {
                            return Formats.ParserResult.error("" + e);
                        }
                    }
                    SDF.parse = parse;
                })(SDF = Molecule.SDF || (Molecule.SDF = {}));
            })(Molecule = Formats.Molecule || (Formats.Molecule = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Molecule;
            (function (Molecule) {
                function parseCIF(type, parse) {
                    var _this = this;
                    return function (data, params) { return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var file, result, mol;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                case 1:
                                    _a.sent();
                                    file = parse(data, params);
                                    if (file.isError) {
                                        throw file.toString();
                                    }
                                    result = file.result;
                                    if (!result.dataBlocks.length) {
                                        throw "The " + type + " data does not contain a data block.";
                                    }
                                    return [4 /*yield*/, ctx.updateProgress('Creating representation...')];
                                case 2:
                                    _a.sent();
                                    mol = Molecule.mmCIF.ofDataBlock(result.dataBlocks[0]);
                                    return [2 /*return*/, Formats.ParserResult.success(mol, result.dataBlocks.length > 1 ? ["The input data contains multiple data blocks, only the first one was parsed. To parse all data blocks, use the function 'mmCIF.ofDataBlock' separately for each block."] : void 0)];
                            }
                        });
                    }); }); };
                }
                var SupportedFormats;
                (function (SupportedFormats) {
                    var _this = this;
                    SupportedFormats.mmCIF = {
                        name: 'mmCIF',
                        shortcuts: ['mmcif', 'cif'],
                        extensions: ['.cif'],
                        parse: parseCIF('CIF', Formats.CIF.Text.parse)
                    };
                    SupportedFormats.mmBCIF = {
                        name: 'mmCIF (Binary)',
                        shortcuts: ['mmbcif', 'bcif', 'binarycif'],
                        extensions: ['.bcif'],
                        isBinary: true,
                        parse: parseCIF('BinaryCIF', Formats.CIF.Binary.parse)
                    };
                    SupportedFormats.PDB = {
                        name: 'PDB',
                        shortcuts: ['pdb', 'ent'],
                        extensions: ['.pdb', '.ent'],
                        parse: parseCIF('PDB', function (d, p) { return Molecule.PDB.toCifFile((p && p.id) || 'PDB', d); })
                    };
                    SupportedFormats.SDF = {
                        name: 'SDF',
                        shortcuts: ['sdf', 'mol'],
                        extensions: ['.sdf', '.mol'],
                        parse: function (data, options) {
                            return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                                var mol;
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                        case 1:
                                            _a.sent();
                                            mol = Molecule.SDF.parse(data, (options && options.id) || undefined);
                                            if (mol.isError)
                                                throw mol.toString();
                                            return [2 /*return*/, Formats.ParserResult.success(mol.result)];
                                    }
                                });
                            }); });
                        }
                    };
                    SupportedFormats.All = [SupportedFormats.mmCIF, SupportedFormats.mmBCIF, SupportedFormats.PDB, SupportedFormats.SDF];
                })(SupportedFormats = Molecule.SupportedFormats || (Molecule.SupportedFormats = {}));
            })(Molecule = Formats.Molecule || (Formats.Molecule = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Density;
            (function (Density) {
                "use strict";
                function fill(data, value) {
                    var len = data.length;
                    for (var i = 0; i < len; i++) {
                        data[i] = value;
                    }
                }
                /**
                 * A field with the Z axis being the slowest and the X being the fastest.
                 */
                var Field3DZYX = /** @class */ (function () {
                    function Field3DZYX(data, dimensions) {
                        this.data = data;
                        this.dimensions = dimensions;
                        this.len = this.dimensions[0] * this.dimensions[1] * this.dimensions[2];
                        this.nX = this.dimensions[0];
                        this.nY = this.dimensions[1];
                    }
                    Object.defineProperty(Field3DZYX.prototype, "length", {
                        get: function () {
                            return this.len;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Field3DZYX.prototype.getAt = function (idx) {
                        return this.data[idx];
                    };
                    Field3DZYX.prototype.setAt = function (idx, v) {
                        this.data[idx] = v;
                    };
                    Field3DZYX.prototype.get = function (i, j, k) {
                        return this.data[(this.nX * (k * this.nY + j) + i) | 0];
                    };
                    Field3DZYX.prototype.set = function (i, j, k, v) {
                        this.data[(this.nX * (k * this.nY + j) + i) | 0] = v;
                    };
                    Field3DZYX.prototype.fill = function (v) {
                        fill(this.data, v);
                    };
                    return Field3DZYX;
                }());
                Density.Field3DZYX = Field3DZYX;
                function createSpacegroup(number, size, angles) {
                    var alpha = (Math.PI / 180.0) * angles[0], beta = (Math.PI / 180.0) * angles[1], gamma = (Math.PI / 180.0) * angles[2];
                    var xScale = size[0], yScale = size[1], zScale = size[2];
                    var z1 = Math.cos(beta), z2 = (Math.cos(alpha) - Math.cos(beta) * Math.cos(gamma)) / Math.sin(gamma), z3 = Math.sqrt(1.0 - z1 * z1 - z2 * z2);
                    var x = [xScale, 0.0, 0.0];
                    var y = [Math.cos(gamma) * yScale, Math.sin(gamma) * yScale, 0.0];
                    var z = [z1 * zScale, z2 * zScale, z3 * zScale];
                    return {
                        number: number,
                        size: size,
                        angles: angles,
                        basis: { x: x, y: y, z: z }
                    };
                }
                Density.createSpacegroup = createSpacegroup;
            })(Density = Formats.Density || (Formats.Density = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Density;
            (function (Density) {
                var CCP4;
                (function (CCP4) {
                    function parse(buffer) {
                        return Parser.parse(buffer);
                    }
                    CCP4.parse = parse;
                    /**
                     * Parses CCP4 files.
                     */
                    var Parser;
                    (function (Parser) {
                        function getArray(r, offset, count) {
                            var ret = [];
                            for (var i = 0; i < count; i++) {
                                ret[i] = r(offset + i);
                            }
                            return ret;
                        }
                        /**
                         * Parse CCP4 file according to spec at http://www.ccp4.ac.uk/html/maplib.html
                         * Inspired by PyMOL implementation of the parser.
                         */
                        function parse(buffer) {
                            var headerSize = 1024, headerView = new DataView(buffer, 0, headerSize), warnings = [];
                            var endian = false;
                            var mode = headerView.getInt32(3 * 4, false);
                            if (mode !== 2) {
                                endian = true;
                                mode = headerView.getInt32(3 * 4, true);
                                if (mode !== 2) {
                                    return Formats.ParserResult.error("Only CCP4 mode 2 is supported.");
                                }
                            }
                            var readInt = function (o) { return headerView.getInt32(o * 4, endian); }, readFloat = function (o) { return headerView.getFloat32(o * 4, endian); };
                            var header = {
                                extent: getArray(readInt, 0, 3),
                                mode: mode,
                                nxyzStart: getArray(readInt, 4, 3),
                                grid: getArray(readInt, 7, 3),
                                cellSize: getArray(readFloat, 10, 3),
                                cellAngles: getArray(readFloat, 13, 3),
                                crs2xyz: getArray(readInt, 16, 3),
                                min: readFloat(19),
                                max: readFloat(20),
                                mean: readFloat(21),
                                spacegroupNumber: readInt(22),
                                symBytes: readInt(23),
                                skewFlag: readInt(24),
                                skewMatrix: getArray(readFloat, 25, 9),
                                skewTranslation: getArray(readFloat, 34, 3),
                                origin2k: getArray(readFloat, 49, 3)
                            };
                            var dataOffset = buffer.byteLength - 4 * header.extent[0] * header.extent[1] * header.extent[2];
                            if (dataOffset !== headerSize + header.symBytes) {
                                if (dataOffset === headerSize) {
                                    warnings.push("File contains bogus symmetry record.");
                                }
                                else if (dataOffset < headerSize) {
                                    return Formats.ParserResult.error("File appears truncated and doesn't match header.");
                                }
                                else if ((dataOffset > headerSize) && (dataOffset < (1024 * 1024))) {
                                    // Fix for loading SPIDER files which are larger than usual
                                    // In this specific case, we must absolutely trust the symBytes record
                                    dataOffset = headerSize + header.symBytes;
                                    warnings.push("File is larger than expected and doesn't match header. Continuing file load, good luck!");
                                }
                                else {
                                    return Formats.ParserResult.error("File is MUCH larger than expected and doesn't match header.");
                                }
                            }
                            //const mapp = readInt(52);
                            //const mapStr = String.fromCharCode((mapp & 0xFF)) + String.fromCharCode(((mapp >> 8) & 0xFF)) + String.fromCharCode(((mapp >> 16) & 0xFF)) + String.fromCharCode(((mapp >> 24) & 0xFF));
                            // pretend we've checked the MAP string at offset 52
                            // pretend we've read the symmetry data
                            if (header.grid[0] === 0 && header.extent[0] > 0) {
                                header.grid[0] = header.extent[0] - 1;
                                warnings.push("Fixed X interval count.");
                            }
                            if (header.grid[1] === 0 && header.extent[1] > 0) {
                                header.grid[1] = header.extent[1] - 1;
                                warnings.push("Fixed Y interval count.");
                            }
                            if (header.grid[2] === 0 && header.extent[2] > 0) {
                                header.grid[2] = header.extent[2] - 1;
                                warnings.push("Fixed Z interval count.");
                            }
                            if (header.crs2xyz[0] === 0 && header.crs2xyz[1] === 0 && header.crs2xyz[2] === 0) {
                                warnings.push("All crs2xyz records are zero. Setting crs2xyz to 1, 2, 3.");
                                header.crs2xyz = [1, 2, 3];
                            }
                            if (header.cellSize[0] === 0.0 &&
                                header.cellSize[1] === 0.0 &&
                                header.cellSize[2] === 0.0) {
                                warnings.push("Cell dimensions are all zero. Setting to 1.0, 1.0, 1.0. Map file will not align with other structures.");
                                header.cellSize[0] = 1.0;
                                header.cellSize[1] = 1.0;
                                header.cellSize[2] = 1.0;
                            }
                            var indices = [0, 0, 0];
                            indices[header.crs2xyz[0] - 1] = 0;
                            indices[header.crs2xyz[1] - 1] = 1;
                            indices[header.crs2xyz[2] - 1] = 2;
                            var originGrid;
                            if (header.origin2k[0] === 0.0 && header.origin2k[1] === 0.0 && header.origin2k[2] === 0.0) {
                                originGrid = [header.nxyzStart[indices[0]], header.nxyzStart[indices[1]], header.nxyzStart[indices[2]]];
                            }
                            else {
                                // Use ORIGIN records rather than old n[xyz]start records
                                //   http://www2.mrc-lmb.cam.ac.uk/image2000.html
                                // XXX the ORIGIN field is only used by the EM community, and
                                //     has undefined meaning for non-orthogonal maps and/or
                                //     non-cubic voxels, etc.
                                originGrid = [header.origin2k[indices[0]], header.origin2k[indices[1]], header.origin2k[indices[2]]];
                            }
                            var extent = [header.extent[indices[0]], header.extent[indices[1]], header.extent[indices[2]]];
                            var nativeEndian = new Uint16Array(new Uint8Array([0x12, 0x34]).buffer)[0] === 0x3412;
                            var rawData = endian === nativeEndian
                                ? readRawData1(new Float32Array(buffer, headerSize + header.symBytes, extent[0] * extent[1] * extent[2]), endian, extent, header.extent, indices, header.mean)
                                : readRawData(new DataView(buffer, headerSize + header.symBytes), endian, extent, header.extent, indices, header.mean);
                            var field = new Density.Field3DZYX(rawData.data, extent);
                            var data = {
                                spacegroup: Density.createSpacegroup(header.spacegroupNumber, header.cellSize, header.cellAngles),
                                box: {
                                    origin: [originGrid[0] / header.grid[0], originGrid[1] / header.grid[1], originGrid[2] / header.grid[2]],
                                    dimensions: [extent[0] / header.grid[0], extent[1] / header.grid[1], extent[2] / header.grid[2]],
                                    sampleCount: extent
                                },
                                data: field,
                                valuesInfo: { min: header.min, max: header.max, mean: header.mean, sigma: rawData.sigma }
                            };
                            return Formats.ParserResult.success(data, warnings);
                        }
                        Parser.parse = parse;
                        function readRawData1(view, endian, extent, headerExtent, indices, mean) {
                            var data = new Float32Array(extent[0] * extent[1] * extent[2]), coord = [0, 0, 0], mX, mY, mZ, cX, cY, cZ, xSize, xySize, offset = 0, v = 0.1, sigma = 0.0, t = 0.1, iX = indices[0], iY = indices[1], iZ = indices[2];
                            mX = headerExtent[0];
                            mY = headerExtent[1];
                            mZ = headerExtent[2];
                            xSize = extent[0];
                            xySize = extent[0] * extent[1];
                            for (cZ = 0; cZ < mZ; cZ++) {
                                coord[2] = cZ;
                                for (cY = 0; cY < mY; cY++) {
                                    coord[1] = cY;
                                    for (cX = 0; cX < mX; cX++) {
                                        coord[0] = cX;
                                        v = view[offset];
                                        t = v - mean;
                                        sigma += t * t,
                                            data[coord[iX] + coord[iY] * xSize + coord[iZ] * xySize] = v;
                                        offset += 1;
                                    }
                                }
                            }
                            sigma /= mX * mY * mZ;
                            sigma = Math.sqrt(sigma);
                            return {
                                data: data,
                                sigma: sigma
                            };
                        }
                        function readRawData(view, endian, extent, headerExtent, indices, mean) {
                            var data = new Float32Array(extent[0] * extent[1] * extent[2]), coord = [0, 0, 0], mX, mY, mZ, cX, cY, cZ, xSize, xySize, offset = 0, v = 0.1, sigma = 0.0, t = 0.1, iX = indices[0], iY = indices[1], iZ = indices[2];
                            mX = headerExtent[0];
                            mY = headerExtent[1];
                            mZ = headerExtent[2];
                            xSize = extent[0];
                            xySize = extent[0] * extent[1];
                            for (cZ = 0; cZ < mZ; cZ++) {
                                coord[2] = cZ;
                                for (cY = 0; cY < mY; cY++) {
                                    coord[1] = cY;
                                    for (cX = 0; cX < mX; cX++) {
                                        coord[0] = cX;
                                        v = view.getFloat32(offset, endian);
                                        t = v - mean;
                                        sigma += t * t,
                                            data[coord[iX] + coord[iY] * xSize + coord[iZ] * xySize] = v;
                                        offset += 4;
                                    }
                                }
                            }
                            sigma /= mX * mY * mZ;
                            sigma = Math.sqrt(sigma);
                            return {
                                data: data,
                                sigma: sigma
                            };
                        }
                    })(Parser || (Parser = {}));
                })(CCP4 = Density.CCP4 || (Density.CCP4 = {}));
            })(Density = Formats.Density || (Formats.Density = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Density;
            (function (Density) {
                var CIF;
                (function (CIF) {
                    function parse(block) {
                        if (block.getCategory('_density_info'))
                            return Parser.parseLegacy(block);
                        else if (block.getCategory('_volume_data_3d_info'))
                            return Parser.parse(block);
                        return Formats.ParserResult.error('Invalid data format.');
                    }
                    CIF.parse = parse;
                    var Parser;
                    (function (Parser) {
                        function parse(block) {
                            var info = block.getCategory('_volume_data_3d_info');
                            if (!info)
                                return Formats.ParserResult.error('_volume_data_3d_info category is missing.');
                            if (!block.getCategory('_volume_data_3d'))
                                return Formats.ParserResult.error('_volume_data_3d category is missing.');
                            function getVector3(name) {
                                var ret = [0, 0, 0];
                                for (var i = 0; i < 3; i++) {
                                    ret[i] = info.getColumn(name + "[" + i + "]").getFloat(0);
                                }
                                return ret;
                            }
                            function getNum(name) { return info.getColumn(name).getFloat(0); }
                            var header = {
                                name: info.getColumn('name').getString(0),
                                axisOrder: getVector3('axis_order'),
                                origin: getVector3('origin'),
                                dimensions: getVector3('dimensions'),
                                sampleCount: getVector3('sample_count'),
                                spacegroupNumber: getNum('spacegroup_number') | 0,
                                cellSize: getVector3('spacegroup_cell_size'),
                                cellAngles: getVector3('spacegroup_cell_angles'),
                                mean: getNum('mean_sampled'),
                                sigma: getNum('sigma_sampled')
                            };
                            var indices = [0, 0, 0];
                            indices[header.axisOrder[0]] = 0;
                            indices[header.axisOrder[1]] = 1;
                            indices[header.axisOrder[2]] = 2;
                            function normalizeOrder(xs) {
                                return [xs[indices[0]], xs[indices[1]], xs[indices[2]]];
                            }
                            var sampleCount = normalizeOrder(header.sampleCount);
                            var rawData = readValues(block.getCategory('_volume_data_3d').getColumn('values'), sampleCount, header.sampleCount, indices);
                            var field = new Density.Field3DZYX(rawData.data, sampleCount);
                            var data = {
                                name: header.name,
                                spacegroup: Density.createSpacegroup(header.spacegroupNumber, header.cellSize, header.cellAngles),
                                box: {
                                    origin: normalizeOrder(header.origin),
                                    dimensions: normalizeOrder(header.dimensions),
                                    sampleCount: sampleCount
                                },
                                data: field,
                                valuesInfo: { min: rawData.min, max: rawData.max, mean: header.mean, sigma: header.sigma }
                            };
                            return Formats.ParserResult.success(data);
                        }
                        Parser.parse = parse;
                        function parseLegacy(block) {
                            var info = block.getCategory('_density_info');
                            if (!info)
                                return Formats.ParserResult.error('_density_info category is missing.');
                            if (!block.getCategory('_density_data'))
                                return Formats.ParserResult.error('_density_data category is missing.');
                            function getArray(name) {
                                var ret = [];
                                for (var i = 0; i < 3; i++) {
                                    ret[i] = info.getColumn(name + "[" + i + "]").getFloat(0);
                                }
                                return ret;
                            }
                            function getNum(name) { return info.getColumn(name).getFloat(0); }
                            var header = {
                                name: info.getColumn('name').getString(0),
                                grid: getArray('grid'),
                                axisOrder: getArray('axis_order'),
                                extent: getArray('extent'),
                                origin: getArray('origin'),
                                cellSize: getArray('cell_size'),
                                cellAngles: getArray('cell_angles'),
                                mean: getNum('mean'),
                                sigma: getNum('sigma'),
                                spacegroupNumber: getNum('spacegroup_number') | 0,
                            };
                            var indices = [0, 0, 0];
                            indices[header.axisOrder[0]] = 0;
                            indices[header.axisOrder[1]] = 1;
                            indices[header.axisOrder[2]] = 2;
                            var originGrid = [header.origin[indices[0]], header.origin[indices[1]], header.origin[indices[2]]];
                            var xyzSampleCount = [header.extent[indices[0]], header.extent[indices[1]], header.extent[indices[2]]];
                            var rawData = readValues(block.getCategory('_density_data').getColumn('values'), xyzSampleCount, header.extent, indices);
                            var field = new Density.Field3DZYX(rawData.data, xyzSampleCount);
                            var data = {
                                name: header.name,
                                spacegroup: Density.createSpacegroup(header.spacegroupNumber, header.cellSize, header.cellAngles),
                                box: {
                                    origin: [originGrid[0] / header.grid[0], originGrid[1] / header.grid[1], originGrid[2] / header.grid[2]],
                                    dimensions: [xyzSampleCount[0] / header.grid[0], xyzSampleCount[1] / header.grid[1], xyzSampleCount[2] / header.grid[2]],
                                    sampleCount: xyzSampleCount
                                },
                                data: field,
                                valuesInfo: { min: rawData.min, max: rawData.max, mean: header.mean, sigma: header.sigma }
                            };
                            return Formats.ParserResult.success(data);
                        }
                        Parser.parseLegacy = parseLegacy;
                        function readValues(col, xyzSampleCount, sampleCount, axisIndices) {
                            var data = new Float32Array(xyzSampleCount[0] * xyzSampleCount[1] * xyzSampleCount[2]);
                            var coord = [0, 0, 0];
                            var iX = axisIndices[0], iY = axisIndices[1], iZ = axisIndices[2];
                            var mX = sampleCount[0], mY = sampleCount[1], mZ = sampleCount[2];
                            var xSize = xyzSampleCount[0];
                            var xySize = xyzSampleCount[0] * xyzSampleCount[1];
                            var offset = 0;
                            var min = col.getFloat(0), max = min;
                            for (var cZ = 0; cZ < mZ; cZ++) {
                                coord[2] = cZ;
                                for (var cY = 0; cY < mY; cY++) {
                                    coord[1] = cY;
                                    for (var cX = 0; cX < mX; cX++) {
                                        coord[0] = cX;
                                        var v = col.getFloat(offset);
                                        offset += 1;
                                        data[coord[iX] + coord[iY] * xSize + coord[iZ] * xySize] = v;
                                        if (v < min)
                                            min = v;
                                        else if (v > max)
                                            max = v;
                                    }
                                }
                            }
                            return { data: data, min: min, max: max };
                        }
                    })(Parser || (Parser = {}));
                })(CIF = Density.CIF || (Density.CIF = {}));
            })(Density = Formats.Density || (Formats.Density = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Formats;
        (function (Formats) {
            var Density;
            (function (Density) {
                function parse(data, name, parser) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, ctx.updateProgress("Parsing " + name + "...")];
                                case 1:
                                    _a.sent();
                                    return [2 /*return*/, parser(data)];
                            }
                        });
                    }); });
                }
                var SupportedFormats;
                (function (SupportedFormats) {
                    SupportedFormats.CCP4 = { name: 'CCP4', shortcuts: ['ccp4', 'map'], extensions: ['.ccp4', '.map'], isBinary: true, parse: function (data) { return parse(data, 'CCP4', function (d) { return Density.CCP4.parse(d); }); } };
                    SupportedFormats.All = [SupportedFormats.CCP4];
                })(SupportedFormats = Density.SupportedFormats || (Density.SupportedFormats = {}));
            })(Density = Formats.Density || (Formats.Density = {}));
        })(Formats = Core.Formats || (Core.Formats = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var LinearAlgebra;
            (function (LinearAlgebra) {
                /*
                 * This code has been modified from https://github.com/toji/gl-matrix/,
                 * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
                 *
                 * 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:
                 */
                function Matrix4() {
                    return Matrix4.zero();
                }
                LinearAlgebra.Matrix4 = Matrix4;
                /**
                 * Stores a 4x4 matrix in a column major (j * 4 + i indexing) format.
                 */
                (function (Matrix4) {
                    function zero() {
                        // force double backing array by 0.1.
                        var ret = [0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
                        ret[0] = 0.0;
                        return ret;
                    }
                    Matrix4.zero = zero;
                    function identity() {
                        var out = zero();
                        out[0] = 1;
                        out[1] = 0;
                        out[2] = 0;
                        out[3] = 0;
                        out[4] = 0;
                        out[5] = 1;
                        out[6] = 0;
                        out[7] = 0;
                        out[8] = 0;
                        out[9] = 0;
                        out[10] = 1;
                        out[11] = 0;
                        out[12] = 0;
                        out[13] = 0;
                        out[14] = 0;
                        out[15] = 1;
                        return out;
                    }
                    Matrix4.identity = identity;
                    function fromIdentity(mat) {
                        mat[0] = 1;
                        mat[1] = 0;
                        mat[2] = 0;
                        mat[3] = 0;
                        mat[4] = 0;
                        mat[5] = 1;
                        mat[6] = 0;
                        mat[7] = 0;
                        mat[8] = 0;
                        mat[9] = 0;
                        mat[10] = 1;
                        mat[11] = 0;
                        mat[12] = 0;
                        mat[13] = 0;
                        mat[14] = 0;
                        mat[15] = 1;
                        return mat;
                    }
                    Matrix4.fromIdentity = fromIdentity;
                    function ofRows(rows) {
                        var out = zero(), i, j, r;
                        for (i = 0; i < 4; i++) {
                            r = rows[i];
                            for (j = 0; j < 4; j++) {
                                out[4 * j + i] = r[j];
                            }
                        }
                        return out;
                    }
                    Matrix4.ofRows = ofRows;
                    function areEqual(a, b, eps) {
                        for (var i = 0; i < 16; i++) {
                            if (Math.abs(a[i] - b[i]) > eps) {
                                return false;
                            }
                        }
                        return true;
                    }
                    Matrix4.areEqual = areEqual;
                    function setValue(a, i, j, value) {
                        a[4 * j + i] = value;
                    }
                    Matrix4.setValue = setValue;
                    function copy(out, a) {
                        out[0] = a[0];
                        out[1] = a[1];
                        out[2] = a[2];
                        out[3] = a[3];
                        out[4] = a[4];
                        out[5] = a[5];
                        out[6] = a[6];
                        out[7] = a[7];
                        out[8] = a[8];
                        out[9] = a[9];
                        out[10] = a[10];
                        out[11] = a[11];
                        out[12] = a[12];
                        out[13] = a[13];
                        out[14] = a[14];
                        out[15] = a[15];
                        return out;
                    }
                    Matrix4.copy = copy;
                    function clone(a) {
                        return Matrix4.copy(Matrix4.zero(), a);
                    }
                    Matrix4.clone = clone;
                    function invert(out, a) {
                        var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32, 
                        // Calculate the determinant
                        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
                        if (!det) {
                            return null;
                        }
                        det = 1.0 / det;
                        out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
                        out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
                        out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
                        out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
                        out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
                        out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
                        out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
                        out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
                        out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
                        out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
                        out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
                        out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
                        out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
                        out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
                        out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
                        out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
                        return out;
                    }
                    Matrix4.invert = invert;
                    function mul(out, a, b) {
                        var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
                        // Cache only the current line of the second matrix
                        var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
                        out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
                        out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
                        out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
                        out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
                        b0 = b[4];
                        b1 = b[5];
                        b2 = b[6];
                        b3 = b[7];
                        out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
                        out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
                        out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
                        out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
                        b0 = b[8];
                        b1 = b[9];
                        b2 = b[10];
                        b3 = b[11];
                        out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
                        out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
                        out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
                        out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
                        b0 = b[12];
                        b1 = b[13];
                        b2 = b[14];
                        b3 = b[15];
                        out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
                        out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
                        out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
                        out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
                        return out;
                    }
                    Matrix4.mul = mul;
                    function mul3(out, a, b, c) {
                        return mul(out, mul(out, a, b), c);
                    }
                    Matrix4.mul3 = mul3;
                    function translate(out, a, v) {
                        var x = v[0], y = v[1], z = v[2], a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23;
                        if (a === out) {
                            out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
                            out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
                            out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
                            out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
                        }
                        else {
                            a00 = a[0];
                            a01 = a[1];
                            a02 = a[2];
                            a03 = a[3];
                            a10 = a[4];
                            a11 = a[5];
                            a12 = a[6];
                            a13 = a[7];
                            a20 = a[8];
                            a21 = a[9];
                            a22 = a[10];
                            a23 = a[11];
                            out[0] = a00;
                            out[1] = a01;
                            out[2] = a02;
                            out[3] = a03;
                            out[4] = a10;
                            out[5] = a11;
                            out[6] = a12;
                            out[7] = a13;
                            out[8] = a20;
                            out[9] = a21;
                            out[10] = a22;
                            out[11] = a23;
                            out[12] = a00 * x + a10 * y + a20 * z + a[12];
                            out[13] = a01 * x + a11 * y + a21 * z + a[13];
                            out[14] = a02 * x + a12 * y + a22 * z + a[14];
                            out[15] = a03 * x + a13 * y + a23 * z + a[15];
                        }
                        return out;
                    }
                    Matrix4.translate = translate;
                    function fromTranslation(out, v) {
                        out[0] = 1;
                        out[1] = 0;
                        out[2] = 0;
                        out[3] = 0;
                        out[4] = 0;
                        out[5] = 1;
                        out[6] = 0;
                        out[7] = 0;
                        out[8] = 0;
                        out[9] = 0;
                        out[10] = 1;
                        out[11] = 0;
                        out[12] = v[0];
                        out[13] = v[1];
                        out[14] = v[2];
                        out[15] = 1;
                        return out;
                    }
                    Matrix4.fromTranslation = fromTranslation;
                    function rotate(out, a, rad, axis) {
                        var x = axis[0], y = axis[1], z = axis[2], len = Math.sqrt(x * x + y * y + z * z), s, c, t, a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23, b00, b01, b02, b10, b11, b12, b20, b21, b22;
                        if (Math.abs(len) < 0.000001 /* Value */) {
                            return null;
                        }
                        len = 1 / len;
                        x *= len;
                        y *= len;
                        z *= len;
                        s = Math.sin(rad);
                        c = Math.cos(rad);
                        t = 1 - c;
                        a00 = a[0];
                        a01 = a[1];
                        a02 = a[2];
                        a03 = a[3];
                        a10 = a[4];
                        a11 = a[5];
                        a12 = a[6];
                        a13 = a[7];
                        a20 = a[8];
                        a21 = a[9];
                        a22 = a[10];
                        a23 = a[11];
                        // Construct the elements of the rotation matrix
                        b00 = x * x * t + c;
                        b01 = y * x * t + z * s;
                        b02 = z * x * t - y * s;
                        b10 = x * y * t - z * s;
                        b11 = y * y * t + c;
                        b12 = z * y * t + x * s;
                        b20 = x * z * t + y * s;
                        b21 = y * z * t - x * s;
                        b22 = z * z * t + c;
                        // Perform rotation-specific matrix multiplication
                        out[0] = a00 * b00 + a10 * b01 + a20 * b02;
                        out[1] = a01 * b00 + a11 * b01 + a21 * b02;
                        out[2] = a02 * b00 + a12 * b01 + a22 * b02;
                        out[3] = a03 * b00 + a13 * b01 + a23 * b02;
                        out[4] = a00 * b10 + a10 * b11 + a20 * b12;
                        out[5] = a01 * b10 + a11 * b11 + a21 * b12;
                        out[6] = a02 * b10 + a12 * b11 + a22 * b12;
                        out[7] = a03 * b10 + a13 * b11 + a23 * b12;
                        out[8] = a00 * b20 + a10 * b21 + a20 * b22;
                        out[9] = a01 * b20 + a11 * b21 + a21 * b22;
                        out[10] = a02 * b20 + a12 * b21 + a22 * b22;
                        out[11] = a03 * b20 + a13 * b21 + a23 * b22;
                        if (a !== out) { // If the source and destination differ, copy the unchanged last row
                            out[12] = a[12];
                            out[13] = a[13];
                            out[14] = a[14];
                            out[15] = a[15];
                        }
                        return out;
                    }
                    Matrix4.rotate = rotate;
                    function fromRotation(out, rad, axis) {
                        var x = axis[0], y = axis[1], z = axis[2], len = Math.sqrt(x * x + y * y + z * z), s, c, t;
                        if (Math.abs(len) < 0.000001 /* Value */) {
                            return fromIdentity(out);
                        }
                        len = 1 / len;
                        x *= len;
                        y *= len;
                        z *= len;
                        s = Math.sin(rad);
                        c = Math.cos(rad);
                        t = 1 - c;
                        // Perform rotation-specific matrix multiplication
                        out[0] = x * x * t + c;
                        out[1] = y * x * t + z * s;
                        out[2] = z * x * t - y * s;
                        out[3] = 0;
                        out[4] = x * y * t - z * s;
                        out[5] = y * y * t + c;
                        out[6] = z * y * t + x * s;
                        out[7] = 0;
                        out[8] = x * z * t + y * s;
                        out[9] = y * z * t - x * s;
                        out[10] = z * z * t + c;
                        out[11] = 0;
                        out[12] = 0;
                        out[13] = 0;
                        out[14] = 0;
                        out[15] = 1;
                        return out;
                    }
                    Matrix4.fromRotation = fromRotation;
                    function scale(out, a, v) {
                        var x = v[0], y = v[1], z = v[2];
                        out[0] = a[0] * x;
                        out[1] = a[1] * x;
                        out[2] = a[2] * x;
                        out[3] = a[3] * x;
                        out[4] = a[4] * y;
                        out[5] = a[5] * y;
                        out[6] = a[6] * y;
                        out[7] = a[7] * y;
                        out[8] = a[8] * z;
                        out[9] = a[9] * z;
                        out[10] = a[10] * z;
                        out[11] = a[11] * z;
                        out[12] = a[12];
                        out[13] = a[13];
                        out[14] = a[14];
                        out[15] = a[15];
                        return out;
                    }
                    Matrix4.scale = scale;
                    function fromScaling(out, v) {
                        out[0] = v[0];
                        out[1] = 0;
                        out[2] = 0;
                        out[3] = 0;
                        out[4] = 0;
                        out[5] = v[1];
                        out[6] = 0;
                        out[7] = 0;
                        out[8] = 0;
                        out[9] = 0;
                        out[10] = v[2];
                        out[11] = 0;
                        out[12] = 0;
                        out[13] = 0;
                        out[14] = 0;
                        out[15] = 1;
                        return out;
                    }
                    Matrix4.fromScaling = fromScaling;
                    function makeTable(m) {
                        var ret = '';
                        for (var i = 0; i < 4; i++) {
                            for (var j = 0; j < 4; j++) {
                                ret += m[4 * j + i].toString();
                                if (j < 3)
                                    ret += ' ';
                            }
                            if (i < 3)
                                ret += '\n';
                        }
                        return ret;
                    }
                    Matrix4.makeTable = makeTable;
                    function determinant(a) {
                        var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32;
                        // Calculate the determinant
                        return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
                    }
                    Matrix4.determinant = determinant;
                })(Matrix4 = LinearAlgebra.Matrix4 || (LinearAlgebra.Matrix4 = {}));
                function Vector3(x, y, z) {
                    return Vector3.fromValues(x || 0, y || 0, z || 0);
                }
                LinearAlgebra.Vector3 = Vector3;
                (function (Vector3) {
                    function zero() {
                        var out = [0.1, 0.0, 0.0];
                        out[0] = 0;
                        return out;
                    }
                    Vector3.zero = zero;
                    function clone(a) {
                        var out = zero();
                        out[0] = a[0];
                        out[1] = a[1];
                        out[2] = a[2];
                        return out;
                    }
                    Vector3.clone = clone;
                    function fromObj(v) {
                        return fromValues(v.x, v.y, v.z);
                    }
                    Vector3.fromObj = fromObj;
                    function toObj(v) {
                        return { x: v[0], y: v[1], z: v[2] };
                    }
                    Vector3.toObj = toObj;
                    function fromValues(x, y, z) {
                        var out = zero();
                        out[0] = x;
                        out[1] = y;
                        out[2] = z;
                        return out;
                    }
                    Vector3.fromValues = fromValues;
                    function set(out, x, y, z) {
                        out[0] = x;
                        out[1] = y;
                        out[2] = z;
                        return out;
                    }
                    Vector3.set = set;
                    function copy(out, a) {
                        out[0] = a[0];
                        out[1] = a[1];
                        out[2] = a[2];
                        return out;
                    }
                    Vector3.copy = copy;
                    function add(out, a, b) {
                        out[0] = a[0] + b[0];
                        out[1] = a[1] + b[1];
                        out[2] = a[2] + b[2];
                        return out;
                    }
                    Vector3.add = add;
                    function sub(out, a, b) {
                        out[0] = a[0] - b[0];
                        out[1] = a[1] - b[1];
                        out[2] = a[2] - b[2];
                        return out;
                    }
                    Vector3.sub = sub;
                    function scale(out, a, b) {
                        out[0] = a[0] * b;
                        out[1] = a[1] * b;
                        out[2] = a[2] * b;
                        return out;
                    }
                    Vector3.scale = scale;
                    function scaleAndAdd(out, a, b, scale) {
                        out[0] = a[0] + (b[0] * scale);
                        out[1] = a[1] + (b[1] * scale);
                        out[2] = a[2] + (b[2] * scale);
                        return out;
                    }
                    Vector3.scaleAndAdd = scaleAndAdd;
                    function distance(a, b) {
                        var x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2];
                        return Math.sqrt(x * x + y * y + z * z);
                    }
                    Vector3.distance = distance;
                    function squaredDistance(a, b) {
                        var x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2];
                        return x * x + y * y + z * z;
                    }
                    Vector3.squaredDistance = squaredDistance;
                    function magnitude(a) {
                        var x = a[0], y = a[1], z = a[2];
                        return Math.sqrt(x * x + y * y + z * z);
                    }
                    Vector3.magnitude = magnitude;
                    function squaredMagnitude(a) {
                        var x = a[0], y = a[1], z = a[2];
                        return x * x + y * y + z * z;
                    }
                    Vector3.squaredMagnitude = squaredMagnitude;
                    function normalize(out, a) {
                        var x = a[0], y = a[1], z = a[2];
                        var len = x * x + y * y + z * z;
                        if (len > 0) {
                            len = 1 / Math.sqrt(len);
                            out[0] = a[0] * len;
                            out[1] = a[1] * len;
                            out[2] = a[2] * len;
                        }
                        return out;
                    }
                    Vector3.normalize = normalize;
                    function dot(a, b) {
                        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
                    }
                    Vector3.dot = dot;
                    function cross(out, a, b) {
                        var ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2];
                        out[0] = ay * bz - az * by;
                        out[1] = az * bx - ax * bz;
                        out[2] = ax * by - ay * bx;
                        return out;
                    }
                    Vector3.cross = cross;
                    function lerp(out, a, b, t) {
                        var ax = a[0], ay = a[1], az = a[2];
                        out[0] = ax + t * (b[0] - ax);
                        out[1] = ay + t * (b[1] - ay);
                        out[2] = az + t * (b[2] - az);
                        return out;
                    }
                    Vector3.lerp = lerp;
                    function transformMat4(out, a, m) {
                        var x = a[0], y = a[1], z = a[2], w = m[3] * x + m[7] * y + m[11] * z + m[15];
                        w = w || 1.0;
                        out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
                        out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
                        out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
                        return out;
                    }
                    Vector3.transformMat4 = transformMat4;
                    var angleTempA = zero(), angleTempB = zero();
                    function angle(a, b) {
                        copy(angleTempA, a);
                        copy(angleTempB, b);
                        normalize(angleTempA, angleTempA);
                        normalize(angleTempB, angleTempB);
                        var cosine = dot(angleTempA, angleTempB);
                        if (cosine > 1.0) {
                            return 0;
                        }
                        else if (cosine < -1.0) {
                            return Math.PI;
                        }
                        else {
                            return Math.acos(cosine);
                        }
                    }
                    Vector3.angle = angle;
                    var rotTemp = zero();
                    function makeRotation(mat, a, b) {
                        var by = angle(a, b);
                        if (Math.abs(by) < 0.0001)
                            return Matrix4.fromIdentity(mat);
                        var axis = cross(rotTemp, a, b);
                        return Matrix4.fromRotation(mat, by, axis);
                    }
                    Vector3.makeRotation = makeRotation;
                })(Vector3 = LinearAlgebra.Vector3 || (LinearAlgebra.Vector3 = {}));
                function Vector4(x, y, z, w) {
                    return Vector4.fromValues(x || 0, y || 0, z || 0, w || 0);
                }
                LinearAlgebra.Vector4 = Vector4;
                (function (Vector4) {
                    function zero() {
                        // force double backing array by 0.1.
                        var ret = [0.1, 0, 0, 0];
                        ret[0] = 0.0;
                        return ret;
                    }
                    Vector4.zero = zero;
                    function clone(a) {
                        var out = zero();
                        out[0] = a[0];
                        out[1] = a[1];
                        out[2] = a[2];
                        out[3] = a[3];
                        return out;
                    }
                    Vector4.clone = clone;
                    function fromValues(x, y, z, w) {
                        var out = zero();
                        out[0] = x;
                        out[1] = y;
                        out[2] = z;
                        out[3] = w;
                        return out;
                    }
                    Vector4.fromValues = fromValues;
                    function set(out, x, y, z, w) {
                        out[0] = x;
                        out[1] = y;
                        out[2] = z;
                        out[3] = w;
                        return out;
                    }
                    Vector4.set = set;
                    function distance(a, b) {
                        var x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2], w = b[3] - a[3];
                        return Math.sqrt(x * x + y * y + z * z + w * w);
                    }
                    Vector4.distance = distance;
                    function squaredDistance(a, b) {
                        var x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2], w = b[3] - a[3];
                        return x * x + y * y + z * z + w * w;
                    }
                    Vector4.squaredDistance = squaredDistance;
                    function norm(a) {
                        var x = a[0], y = a[1], z = a[2], w = a[3];
                        return Math.sqrt(x * x + y * y + z * z + w * w);
                    }
                    Vector4.norm = norm;
                    function squaredNorm(a) {
                        var x = a[0], y = a[1], z = a[2], w = a[3];
                        return x * x + y * y + z * z + w * w;
                    }
                    Vector4.squaredNorm = squaredNorm;
                    function transform(out, a, m) {
                        var x = a[0], y = a[1], z = a[2], w = a[3];
                        out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
                        out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
                        out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
                        out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
                        return out;
                    }
                    Vector4.transform = transform;
                })(Vector4 = LinearAlgebra.Vector4 || (LinearAlgebra.Vector4 = {}));
            })(LinearAlgebra = Geometry.LinearAlgebra || (Geometry.LinearAlgebra = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            "use strict";
            var Surface;
            (function (Surface) {
                var Vec3 = Geometry.LinearAlgebra.Vector3;
                function computeNormalsImmediate(surface) {
                    if (surface.normals)
                        return;
                    var normals = new Float32Array(surface.vertices.length), v = surface.vertices, triangles = surface.triangleIndices;
                    var x = Vec3.zero(), y = Vec3.zero(), z = Vec3.zero(), d1 = Vec3.zero(), d2 = Vec3.zero(), n = Vec3.zero();
                    for (var i = 0; i < triangles.length; i += 3) {
                        var a = 3 * triangles[i], b = 3 * triangles[i + 1], c = 3 * triangles[i + 2];
                        Vec3.set(x, v[a], v[a + 1], v[a + 2]);
                        Vec3.set(y, v[b], v[b + 1], v[b + 2]);
                        Vec3.set(z, v[c], v[c + 1], v[c + 2]);
                        Vec3.sub(d1, z, y);
                        Vec3.sub(d2, y, x);
                        Vec3.cross(n, d1, d2);
                        normals[a] += n[0];
                        normals[a + 1] += n[1];
                        normals[a + 2] += n[2];
                        normals[b] += n[0];
                        normals[b + 1] += n[1];
                        normals[b + 2] += n[2];
                        normals[c] += n[0];
                        normals[c + 1] += n[1];
                        normals[c + 2] += n[2];
                    }
                    for (var i = 0; i < normals.length; i += 3) {
                        var nx = normals[i];
                        var ny = normals[i + 1];
                        var nz = normals[i + 2];
                        var f = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
                        normals[i] *= f;
                        normals[i + 1] *= f;
                        normals[i + 2] *= f;
                    }
                    surface.normals = normals;
                }
                Surface.computeNormalsImmediate = computeNormalsImmediate;
                function computeNormals(surface) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    if (surface.normals) {
                                        return [2 /*return*/, surface];
                                    }
                                    ;
                                    return [4 /*yield*/, ctx.updateProgress('Computing normals...')];
                                case 1:
                                    _a.sent();
                                    computeNormalsImmediate(surface);
                                    return [2 /*return*/, surface];
                            }
                        });
                    }); });
                }
                Surface.computeNormals = computeNormals;
                function addVertex(src, i, dst, j) {
                    dst[3 * j] += src[3 * i];
                    dst[3 * j + 1] += src[3 * i + 1];
                    dst[3 * j + 2] += src[3 * i + 2];
                }
                function laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight) {
                    var triCount = surface.triangleIndices.length, src = surface.vertices;
                    var triangleIndices = surface.triangleIndices;
                    for (var i = 0; i < triCount; i += 3) {
                        var a = triangleIndices[i], b = triangleIndices[i + 1], c = triangleIndices[i + 2];
                        addVertex(src, b, vs, a);
                        addVertex(src, c, vs, a);
                        addVertex(src, a, vs, b);
                        addVertex(src, c, vs, b);
                        addVertex(src, a, vs, c);
                        addVertex(src, b, vs, c);
                    }
                    var vw = 2 * vertexWeight;
                    for (var i = 0, _b = surface.vertexCount; i < _b; i++) {
                        var n = vertexCounts[i] + vw;
                        vs[3 * i] = (vs[3 * i] + vw * src[3 * i]) / n;
                        vs[3 * i + 1] = (vs[3 * i + 1] + vw * src[3 * i + 1]) / n;
                        vs[3 * i + 2] = (vs[3 * i + 2] + vw * src[3 * i + 2]) / n;
                    }
                }
                function laplacianSmoothComputation(ctx, surface, iterCount, vertexWeight) {
                    return __awaiter(this, void 0, void 0, function () {
                        var vertexCounts, triCount, tris, i, vs, started, i, j, _b, t, time;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, ctx.updateProgress('Smoothing surface...', true)];
                                case 1:
                                    _a.sent();
                                    vertexCounts = new Int32Array(surface.vertexCount), triCount = surface.triangleIndices.length;
                                    tris = surface.triangleIndices;
                                    for (i = 0; i < triCount; i++) {
                                        // in a triangle 2 edges touch each vertex, hence the constant.
                                        vertexCounts[tris[i]] += 2;
                                    }
                                    vs = new Float32Array(surface.vertices.length);
                                    started = Core.Utils.PerformanceMonitor.currentTime();
                                    return [4 /*yield*/, ctx.updateProgress('Smoothing surface...', true)];
                                case 2:
                                    _a.sent();
                                    i = 0;
                                    _a.label = 3;
                                case 3:
                                    if (!(i < iterCount)) return [3 /*break*/, 6];
                                    if (i > 0) {
                                        for (j = 0, _b = vs.length; j < _b; j++)
                                            vs[j] = 0;
                                    }
                                    surface.normals = void 0;
                                    laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight);
                                    t = surface.vertices;
                                    surface.vertices = vs;
                                    vs = t;
                                    time = Core.Utils.PerformanceMonitor.currentTime();
                                    if (!(time - started > Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 5];
                                    started = time;
                                    return [4 /*yield*/, ctx.updateProgress('Smoothing surface...', true, i + 1, iterCount)];
                                case 4:
                                    _a.sent();
                                    _a.label = 5;
                                case 5:
                                    i++;
                                    return [3 /*break*/, 3];
                                case 6: return [2 /*return*/, surface];
                            }
                        });
                    });
                }
                /*
                 * Smooths the vertices by averaging the neighborhood.
                 *
                 * Resets normals. Might replace vertex array.
                 */
                function laplacianSmooth(surface, iterCount, vertexWeight) {
                    var _this = this;
                    if (iterCount === void 0) { iterCount = 1; }
                    if (vertexWeight === void 0) { vertexWeight = 1; }
                    if (iterCount < 1)
                        iterCount = 0;
                    if (iterCount === 0)
                        return Core.Computation.resolve(surface);
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1)];
                            case 1: return [2 /*return*/, _a.sent()];
                        }
                    }); }); });
                }
                Surface.laplacianSmooth = laplacianSmooth;
                function computeBoundingSphere(surface) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var vertices, x, y, z, i, _c, r, i, _c, dx, dy, dz;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    if (surface.boundingSphere) {
                                        return [2 /*return*/, surface];
                                    }
                                    return [4 /*yield*/, ctx.updateProgress('Computing bounding sphere...')];
                                case 1:
                                    _a.sent();
                                    vertices = surface.vertices;
                                    x = 0, y = 0, z = 0;
                                    for (i = 0, _c = surface.vertices.length; i < _c; i += 3) {
                                        x += vertices[i];
                                        y += vertices[i + 1];
                                        z += vertices[i + 2];
                                    }
                                    x /= surface.vertexCount;
                                    y /= surface.vertexCount;
                                    z /= surface.vertexCount;
                                    r = 0;
                                    for (i = 0, _c = vertices.length; i < _c; i += 3) {
                                        dx = x - vertices[i];
                                        dy = y - vertices[i + 1];
                                        dz = z - vertices[i + 2];
                                        r = Math.max(r, dx * dx + dy * dy + dz * dz);
                                    }
                                    surface.boundingSphere = {
                                        center: Geometry.LinearAlgebra.Vector3.fromValues(x, y, z),
                                        radius: Math.sqrt(r)
                                    };
                                    return [2 /*return*/, surface];
                            }
                        });
                    }); });
                }
                Surface.computeBoundingSphere = computeBoundingSphere;
                function transformImmediate(surface, t) {
                    var p = Geometry.LinearAlgebra.Vector3.zero();
                    var m = Geometry.LinearAlgebra.Vector3.transformMat4;
                    var vertices = surface.vertices;
                    for (var i = 0, _c = surface.vertices.length; i < _c; i += 3) {
                        p[0] = vertices[i];
                        p[1] = vertices[i + 1];
                        p[2] = vertices[i + 2];
                        m(p, p, t);
                        vertices[i] = p[0];
                        vertices[i + 1] = p[1];
                        vertices[i + 2] = p[2];
                    }
                    surface.normals = void 0;
                    surface.boundingSphere = void 0;
                }
                Surface.transformImmediate = transformImmediate;
                function transform(surface, t) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        return __generator(this, function (_a) {
                            ctx.updateProgress('Updating surface...');
                            transformImmediate(surface, t);
                            return [2 /*return*/, surface];
                        });
                    }); });
                }
                Surface.transform = transform;
            })(Surface = Geometry.Surface || (Geometry.Surface = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var Query3D;
            (function (Query3D) {
                var Box3D;
                (function (Box3D) {
                    function createInfinite() {
                        return {
                            min: [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE],
                            max: [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE]
                        };
                    }
                    Box3D.createInfinite = createInfinite;
                })(Box3D = Query3D.Box3D || (Query3D.Box3D = {}));
                var QueryContext;
                (function (QueryContext) {
                    function add(ctx, distSq, index) {
                        var buffer = ctx.buffer;
                        buffer.squaredDistances[buffer.count] = distSq;
                        buffer.elements[buffer.count++] = buffer.sourceElements[index];
                    }
                    QueryContext.add = add;
                    function resetBuffer(buffer) { buffer.count = 0; }
                    function createBuffer(sourceElements) {
                        return {
                            sourceElements: sourceElements,
                            elements: [],
                            count: 0,
                            squaredDistances: []
                        };
                    }
                    /**
                     * Query the tree and store the result to this.buffer. Overwrites the old result.
                     */
                    function update(ctx, x, y, z, radius) {
                        ctx.pivot[0] = x;
                        ctx.pivot[1] = y;
                        ctx.pivot[2] = z;
                        ctx.radius = radius;
                        ctx.radiusSq = radius * radius;
                        resetBuffer(ctx.buffer);
                    }
                    QueryContext.update = update;
                    function create(structure, sourceElements) {
                        return {
                            structure: structure,
                            buffer: createBuffer(sourceElements),
                            pivot: [0.1, 0.1, 0.1],
                            radius: 1.1,
                            radiusSq: 1.1 * 1.1
                        };
                    }
                    QueryContext.create = create;
                })(QueryContext = Query3D.QueryContext || (Query3D.QueryContext = {}));
                var PositionBuilder;
                (function (PositionBuilder) {
                    function add(builder, x, y, z) {
                        builder.data[builder._count++] = x;
                        builder.data[builder._count++] = y;
                        builder.data[builder._count++] = z;
                        builder.boundsMin[0] = Math.min(x, builder.boundsMin[0]);
                        builder.boundsMin[1] = Math.min(y, builder.boundsMin[1]);
                        builder.boundsMin[2] = Math.min(z, builder.boundsMin[2]);
                        builder.boundsMax[0] = Math.max(x, builder.boundsMax[0]);
                        builder.boundsMax[1] = Math.max(y, builder.boundsMax[1]);
                        builder.boundsMax[2] = Math.max(z, builder.boundsMax[2]);
                    }
                    PositionBuilder.add = add;
                    function create(size) {
                        var data = new Float32Array((size * 3) | 0);
                        var bounds = Box3D.createInfinite();
                        var boundsMin = bounds.min;
                        var boundsMax = bounds.max;
                        return { _count: 0, data: data, bounds: bounds, boundsMin: boundsMin, boundsMax: boundsMax };
                    }
                    PositionBuilder.create = create;
                    function createAdder(builder) {
                        var add = PositionBuilder.add;
                        return function (x, y, z) {
                            add(builder, x, y, z);
                        };
                    }
                    PositionBuilder.createAdder = createAdder;
                })(PositionBuilder || (PositionBuilder = {}));
                function createInputData(elements, f) {
                    var positions = PositionBuilder.create(elements.length);
                    var indices = new Int32Array(elements.length);
                    var add = PositionBuilder.createAdder(positions);
                    for (var i = 0; i < elements.length; i++) {
                        indices[i] = i;
                        f(elements[i], add);
                    }
                    return { elements: elements, positions: positions.data, bounds: positions.bounds, indices: indices };
                }
                Query3D.createInputData = createInputData;
            })(Query3D = Geometry.Query3D || (Geometry.Query3D = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var Query3D;
            (function (Query3D) {
                var SubdivisionTree3DNode;
                (function (SubdivisionTree3DNode) {
                    function nearestLeaf(node, ctx) {
                        var pivot = ctx.pivot, _a = ctx.structure, indices = _a.indices, positions = _a.positions, rSq = ctx.radiusSq, dx, dy, dz, o, m, i;
                        for (i = node.startIndex; i < node.endIndex; i++) {
                            o = 3 * indices[i];
                            dx = pivot[0] - positions[o];
                            dy = pivot[1] - positions[o + 1];
                            dz = pivot[2] - positions[o + 2];
                            m = dx * dx + dy * dy + dz * dz;
                            if (m <= rSq)
                                Query3D.QueryContext.add(ctx, m, indices[i]);
                        }
                    }
                    function nearestNode(node, ctx, dim) {
                        var pivot = ctx.pivot[dim], left = pivot < node.splitValue;
                        if (left ? pivot + ctx.radius > node.splitValue : pivot - ctx.radius < node.splitValue) {
                            nearest(node.left, ctx, (dim + 1) % 3);
                            nearest(node.right, ctx, (dim + 1) % 3);
                        }
                        else if (left) {
                            nearest(node.left, ctx, (dim + 1) % 3);
                        }
                        else {
                            nearest(node.right, ctx, (dim + 1) % 3);
                        }
                    }
                    function nearest(node, ctx, dim) {
                        // check for empty.
                        if (node.startIndex === node.endIndex)
                            return;
                        // is leaf?
                        if (isNaN(node.splitValue))
                            nearestLeaf(node, ctx);
                        else
                            nearestNode(node, ctx, dim);
                    }
                    SubdivisionTree3DNode.nearest = nearest;
                    function create(splitValue, startIndex, endIndex, left, right) {
                        return { splitValue: splitValue, startIndex: startIndex, endIndex: endIndex, left: left, right: right };
                    }
                    SubdivisionTree3DNode.create = create;
                })(SubdivisionTree3DNode || (SubdivisionTree3DNode = {}));
                /**
                 * A helper to build the tree.
                 */
                var SubdivisionTree3DBuilder;
                (function (SubdivisionTree3DBuilder) {
                    function split(state, startIndex, endIndex, coord) {
                        var delta = endIndex - startIndex + 1;
                        if (delta <= 0) {
                            return state.emptyNode;
                        }
                        else if (delta <= state.leafSize) {
                            return SubdivisionTree3DNode.create(NaN, startIndex, endIndex + 1, state.emptyNode, state.emptyNode);
                        }
                        var min = state.bounds.min[coord], max = state.bounds.max[coord], median = 0.5 * (min + max), midIndex = 0, l = startIndex, r = endIndex, t, left, right;
                        while (l < r) {
                            t = state.indices[r];
                            state.indices[r] = state.indices[l];
                            state.indices[l] = t;
                            while (l <= endIndex && state.positions[3 * state.indices[l] + coord] <= median)
                                l++;
                            while (r >= startIndex && state.positions[3 * state.indices[r] + coord] > median)
                                r--;
                        }
                        midIndex = l - 1;
                        state.bounds.max[coord] = median;
                        left = split(state, startIndex, midIndex, (coord + 1) % 3);
                        state.bounds.max[coord] = max;
                        state.bounds.min[coord] = median;
                        right = split(state, midIndex + 1, endIndex, (coord + 1) % 3);
                        state.bounds.min[coord] = min;
                        return SubdivisionTree3DNode.create(median, startIndex, endIndex + 1, left, right);
                    }
                    function build(_a, leafSize) {
                        var elements = _a.elements, positions = _a.positions, bounds = _a.bounds, indices = _a.indices;
                        var state = {
                            bounds: bounds,
                            positions: positions,
                            leafSize: leafSize,
                            indices: indices,
                            emptyNode: SubdivisionTree3DNode.create(NaN, -1, -1, void 0, void 0),
                        };
                        var root = split(state, 0, indices.length - 1, 0);
                        return { root: root, indices: indices, positions: positions };
                    }
                    SubdivisionTree3DBuilder.build = build;
                })(SubdivisionTree3DBuilder || (SubdivisionTree3DBuilder = {}));
                function createSubdivisionTree(data, leafSize) {
                    if (leafSize === void 0) { leafSize = 32; }
                    var tree = SubdivisionTree3DBuilder.build(data, leafSize);
                    return function () {
                        var ctx = Query3D.QueryContext.create(tree, data.elements);
                        return function (x, y, z, radius) {
                            Query3D.QueryContext.update(ctx, x, y, z, radius);
                            SubdivisionTree3DNode.nearest(tree.root, ctx, 0);
                            return ctx.buffer;
                        };
                    };
                }
                Query3D.createSubdivisionTree = createSubdivisionTree;
            })(Query3D = Geometry.Query3D || (Geometry.Query3D = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var Query3D;
            (function (Query3D) {
                /**
                 * Adapted from https://github.com/arose/ngl
                 * MIT License Copyright (C) 2014+ Alexander Rose
                 */
                function nearest(ctx) {
                    var _a = ctx.structure, _b = _a.min, minX = _b[0], minY = _b[1], minZ = _b[2], _c = _a.size, sX = _c[0], sY = _c[1], sZ = _c[2], bucketOffset = _a.bucketOffset, bucketCounts = _a.bucketCounts, bucketArray = _a.bucketArray, grid = _a.grid, positions = _a.positions;
                    var r = ctx.radius, rSq = ctx.radiusSq, _d = ctx.pivot, x = _d[0], y = _d[1], z = _d[2];
                    var loX = Math.max(0, (x - r - minX) >> 3 /* Exp */);
                    var loY = Math.max(0, (y - r - minY) >> 3 /* Exp */);
                    var loZ = Math.max(0, (z - r - minZ) >> 3 /* Exp */);
                    var hiX = Math.min(sX, (x + r - minX) >> 3 /* Exp */);
                    var hiY = Math.min(sY, (y + r - minY) >> 3 /* Exp */);
                    var hiZ = Math.min(sZ, (z + r - minZ) >> 3 /* Exp */);
                    for (var ix = loX; ix <= hiX; ix++) {
                        for (var iy = loY; iy <= hiY; iy++) {
                            for (var iz = loZ; iz <= hiZ; iz++) {
                                var idx = (((ix * sY) + iy) * sZ) + iz;
                                var bucketIdx = grid[idx];
                                if (bucketIdx > 0) {
                                    var k = bucketIdx - 1;
                                    var offset = bucketOffset[k];
                                    var count = bucketCounts[k];
                                    var end = offset + count;
                                    for (var i = offset; i < end; i++) {
                                        var idx_1 = bucketArray[i];
                                        var dx = positions[3 * idx_1 + 0] - x;
                                        var dy = positions[3 * idx_1 + 1] - y;
                                        var dz = positions[3 * idx_1 + 2] - z;
                                        var distSq = dx * dx + dy * dy + dz * dz;
                                        if (distSq <= rSq) {
                                            Query3D.QueryContext.add(ctx, distSq, idx_1);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                function _build(state) {
                    var bounds = state.bounds, _a = state.size, sX = _a[0], sY = _a[1], sZ = _a[2], positions = state.positions, indices = state.indices;
                    var n = sX * sY * sZ;
                    var count = indices.length;
                    var _b = bounds.min, minX = _b[0], minY = _b[1], minZ = _b[2];
                    var bucketCount = 0;
                    var grid = new Uint32Array(n);
                    var bucketIndex = new Int32Array(count);
                    for (var i = 0; i < count; i++) {
                        var x = (positions[3 * i + 0] - minX) >> 3 /* Exp */;
                        var y = (positions[3 * i + 1] - minY) >> 3 /* Exp */;
                        var z = (positions[3 * i + 2] - minZ) >> 3 /* Exp */;
                        var idx = (((x * sY) + y) * sZ) + z;
                        if ((grid[idx] += 1) === 1) {
                            bucketCount += 1;
                        }
                        bucketIndex[i] = idx;
                    }
                    var bucketCounts = new Int32Array(bucketCount);
                    for (var i = 0, j = 0; i < n; i++) {
                        var c = grid[i];
                        if (c > 0) {
                            grid[i] = j + 1;
                            bucketCounts[j] = c;
                            j += 1;
                        }
                    }
                    var bucketOffset = new Uint32Array(count);
                    for (var i = 1; i < count; ++i) {
                        bucketOffset[i] += bucketOffset[i - 1] + bucketCounts[i - 1];
                    }
                    var bucketFill = new Int32Array(bucketCount);
                    var bucketArray = new Int32Array(count);
                    for (var i = 0; i < count; i++) {
                        var bucketIdx = grid[bucketIndex[i]];
                        if (bucketIdx > 0) {
                            var k = bucketIdx - 1;
                            bucketArray[bucketOffset[k] + bucketFill[k]] = i;
                            bucketFill[k] += 1;
                        }
                    }
                    return {
                        size: state.size,
                        bucketArray: bucketArray,
                        bucketCounts: bucketCounts,
                        bucketOffset: bucketOffset,
                        grid: grid,
                        min: state.bounds.min,
                        positions: positions
                    };
                }
                function build(_a) {
                    var elements = _a.elements, positions = _a.positions, bounds = _a.bounds, indices = _a.indices;
                    var size = [
                        ((bounds.max[0] - bounds.min[0]) >> 3 /* Exp */) + 1,
                        ((bounds.max[1] - bounds.min[1]) >> 3 /* Exp */) + 1,
                        ((bounds.max[2] - bounds.min[2]) >> 3 /* Exp */) + 1
                    ];
                    var state = {
                        size: size,
                        positions: positions,
                        indices: indices,
                        bounds: bounds
                    };
                    return _build(state);
                }
                function createSpatialHash(data) {
                    var tree = build(data);
                    return function () {
                        var ctx = Query3D.QueryContext.create(tree, data.elements);
                        return function (x, y, z, radius) {
                            Query3D.QueryContext.update(ctx, x, y, z, radius);
                            nearest(ctx);
                            return ctx.buffer;
                        };
                    };
                }
                Query3D.createSpatialHash = createSpatialHash;
            })(Query3D = Geometry.Query3D || (Geometry.Query3D = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var MarchingCubes;
            (function (MarchingCubes) {
                "use strict";
                function compute(parameters) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var comp;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    comp = new MarchingCubesComputation(parameters, ctx);
                                    return [4 /*yield*/, comp.run()];
                                case 1: return [2 /*return*/, _a.sent()];
                            }
                        });
                    }); });
                }
                MarchingCubes.compute = compute;
                var MarchingCubesComputation = /** @class */ (function () {
                    function MarchingCubesComputation(parameters, ctx) {
                        this.ctx = ctx;
                        this.minX = 0;
                        this.minY = 0;
                        this.minZ = 0;
                        this.maxX = 0;
                        this.maxY = 0;
                        this.maxZ = 0;
                        var params = Core.Utils.extend({}, parameters);
                        if (!params.bottomLeft)
                            params.bottomLeft = [0, 0, 0];
                        if (!params.topRight)
                            params.topRight = params.scalarField.dimensions;
                        this.state = new MarchingCubesState(params),
                            this.minX = params.bottomLeft[0];
                        this.minY = params.bottomLeft[1];
                        this.minZ = params.bottomLeft[2];
                        this.maxX = params.topRight[0] - 1;
                        this.maxY = params.topRight[1] - 1;
                        this.maxZ = params.topRight[2] - 1;
                        this.size = (this.maxX - this.minX) * (this.maxY - this.minY) * (this.maxZ - this.minZ);
                        this.sliceSize = (this.maxX - this.minX) * (this.maxY - this.minY);
                    }
                    MarchingCubesComputation.prototype.doSlices = function () {
                        return __awaiter(this, void 0, void 0, function () {
                            var done, started, k, t;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        done = 0;
                                        started = Core.Utils.PerformanceMonitor.currentTime();
                                        k = this.minZ;
                                        _a.label = 1;
                                    case 1:
                                        if (!(k < this.maxZ)) return [3 /*break*/, 4];
                                        this.slice(k);
                                        done += this.sliceSize;
                                        t = Core.Utils.PerformanceMonitor.currentTime();
                                        if (!(t - started > Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 3];
                                        return [4 /*yield*/, this.ctx.updateProgress('Computing surface...', true, done, this.size)];
                                    case 2:
                                        _a.sent();
                                        started = t;
                                        _a.label = 3;
                                    case 3:
                                        k++;
                                        return [3 /*break*/, 1];
                                    case 4: return [2 /*return*/];
                                }
                            });
                        });
                    };
                    MarchingCubesComputation.prototype.slice = function (k) {
                        for (var j = this.minY; j < this.maxY; j++) {
                            for (var i = this.minX; i < this.maxX; i++) {
                                this.state.processCell(i, j, k);
                            }
                        }
                        this.state.clearEdgeVertexIndexSlice(k);
                    };
                    MarchingCubesComputation.prototype.finish = function () {
                        var vertices = Core.Utils.ChunkedArray.compact(this.state.vertexBuffer);
                        var triangles = Core.Utils.ChunkedArray.compact(this.state.triangleBuffer);
                        this.state.vertexBuffer = void 0;
                        this.state.verticesOnEdges = void 0;
                        var ret = {
                            vertexCount: (vertices.length / 3) | 0,
                            triangleCount: (triangles.length / 3) | 0,
                            vertices: vertices,
                            triangleIndices: triangles,
                            annotation: this.state.annotate ? Core.Utils.ChunkedArray.compact(this.state.annotationBuffer) : void 0
                        };
                        return ret;
                    };
                    MarchingCubesComputation.prototype.run = function () {
                        return __awaiter(this, void 0, void 0, function () {
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, this.ctx.updateProgress('Computing surface...', true, 0, this.size)];
                                    case 1:
                                        _a.sent();
                                        return [4 /*yield*/, this.doSlices()];
                                    case 2:
                                        _a.sent();
                                        return [4 /*yield*/, this.ctx.updateProgress('Finalizing...')];
                                    case 3:
                                        _a.sent();
                                        return [2 /*return*/, this.finish()];
                                }
                            });
                        });
                    };
                    return MarchingCubesComputation;
                }());
                var MarchingCubesState = /** @class */ (function () {
                    function MarchingCubesState(params) {
                        this.vertList = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
                        this.i = 0;
                        this.j = 0;
                        this.k = 0;
                        this.nX = params.scalarField.dimensions[0];
                        this.nY = params.scalarField.dimensions[1];
                        this.nZ = params.scalarField.dimensions[2];
                        this.isoLevel = params.isoLevel;
                        this.scalarField = params.scalarField;
                        this.annotationField = params.annotationField;
                        var dX = params.topRight[0] - params.bottomLeft[0], dY = params.topRight[1] - params.bottomLeft[1], dZ = params.topRight[2] - params.bottomLeft[2], vertexBufferSize = Math.min(262144, Math.max(dX * dY * dZ / 16, 1024) | 0), triangleBufferSize = Math.min(1 << 16, vertexBufferSize * 4);
                        this.vertexBuffer = Core.Utils.ChunkedArray.forVertex3D(vertexBufferSize);
                        this.triangleBuffer = Core.Utils.ChunkedArray.create(function (size) { return new Uint32Array(size); }, triangleBufferSize, 3);
                        this.annotate = !!params.annotationField;
                        if (this.annotate)
                            this.annotationBuffer = Core.Utils.ChunkedArray.forInt32(vertexBufferSize);
                        // two layers of vertex indices. Each vertex has 3 edges associated.
                        this.verticesOnEdges = new Int32Array(3 * this.nX * this.nY * 2);
                    }
                    MarchingCubesState.prototype.get3dOffsetFromEdgeInfo = function (index) {
                        return (this.nX * (((this.k + index.k) % 2) * this.nY + this.j + index.j) + this.i + index.i);
                    };
                    /**
                     * This clears the "vertex index buffer" for the slice that will not be accessed anymore.
                     */
                    MarchingCubesState.prototype.clearEdgeVertexIndexSlice = function (k) {
                        // clear either the top or bottom half of the buffer...
                        var start = k % 2 === 0 ? 0 : 3 * this.nX * this.nY;
                        var end = k % 2 === 0 ? 3 * this.nX * this.nY : this.verticesOnEdges.length;
                        for (var i = start; i < end; i++)
                            this.verticesOnEdges[i] = 0;
                    };
                    MarchingCubesState.prototype.interpolate = function (edgeNum) {
                        var info = MarchingCubes.EdgeIdInfo[edgeNum], edgeId = 3 * this.get3dOffsetFromEdgeInfo(info) + info.e;
                        var ret = this.verticesOnEdges[edgeId];
                        if (ret > 0)
                            return (ret - 1) | 0;
                        var edge = MarchingCubes.CubeEdges[edgeNum];
                        var a = edge.a, b = edge.b;
                        var li = a.i + this.i, lj = a.j + this.j, lk = a.k + this.k;
                        var hi = b.i + this.i, hj = b.j + this.j, hk = b.k + this.k;
                        var v0 = this.scalarField.get(li, lj, lk), v1 = this.scalarField.get(hi, hj, hk);
                        var t = (this.isoLevel - v0) / (v0 - v1);
                        var id = Core.Utils.ChunkedArray.add3(this.vertexBuffer, li + t * (li - hi), lj + t * (lj - hj), lk + t * (lk - hk)) | 0;
                        this.verticesOnEdges[edgeId] = id + 1;
                        if (this.annotate) {
                            var a_1 = t < 0.5 ? this.annotationField.get(li, lj, lk) : this.annotationField.get(hi, hj, hk);
                            if (a_1 < 0)
                                a_1 = t < 0.5 ? this.annotationField.get(hi, hj, hk) : this.annotationField.get(li, lj, lk);
                            Core.Utils.ChunkedArray.add(this.annotationBuffer, a_1);
                        }
                        return id;
                    };
                    MarchingCubesState.prototype.processCell = function (i, j, k) {
                        var tableIndex = 0;
                        if (this.scalarField.get(i, j, k) < this.isoLevel)
                            tableIndex |= 1;
                        if (this.scalarField.get(i + 1, j, k) < this.isoLevel)
                            tableIndex |= 2;
                        if (this.scalarField.get(i + 1, j + 1, k) < this.isoLevel)
                            tableIndex |= 4;
                        if (this.scalarField.get(i, j + 1, k) < this.isoLevel)
                            tableIndex |= 8;
                        if (this.scalarField.get(i, j, k + 1) < this.isoLevel)
                            tableIndex |= 16;
                        if (this.scalarField.get(i + 1, j, k + 1) < this.isoLevel)
                            tableIndex |= 32;
                        if (this.scalarField.get(i + 1, j + 1, k + 1) < this.isoLevel)
                            tableIndex |= 64;
                        if (this.scalarField.get(i, j + 1, k + 1) < this.isoLevel)
                            tableIndex |= 128;
                        if (tableIndex === 0 || tableIndex === 255)
                            return;
                        this.i = i;
                        this.j = j;
                        this.k = k;
                        var edgeInfo = MarchingCubes.EdgeTable[tableIndex];
                        if ((edgeInfo & 1) > 0)
                            this.vertList[0] = this.interpolate(0); // 0 1
                        if ((edgeInfo & 2) > 0)
                            this.vertList[1] = this.interpolate(1); // 1 2
                        if ((edgeInfo & 4) > 0)
                            this.vertList[2] = this.interpolate(2); // 2 3
                        if ((edgeInfo & 8) > 0)
                            this.vertList[3] = this.interpolate(3); // 0 3
                        if ((edgeInfo & 16) > 0)
                            this.vertList[4] = this.interpolate(4); // 4 5
                        if ((edgeInfo & 32) > 0)
                            this.vertList[5] = this.interpolate(5); // 5 6
                        if ((edgeInfo & 64) > 0)
                            this.vertList[6] = this.interpolate(6); // 6 7
                        if ((edgeInfo & 128) > 0)
                            this.vertList[7] = this.interpolate(7); // 4 7
                        if ((edgeInfo & 256) > 0)
                            this.vertList[8] = this.interpolate(8); // 0 4
                        if ((edgeInfo & 512) > 0)
                            this.vertList[9] = this.interpolate(9); // 1 5
                        if ((edgeInfo & 1024) > 0)
                            this.vertList[10] = this.interpolate(10); // 2 6
                        if ((edgeInfo & 2048) > 0)
                            this.vertList[11] = this.interpolate(11); // 3 7
                        var triInfo = MarchingCubes.TriTable[tableIndex];
                        for (var t = 0; t < triInfo.length; t += 3) {
                            Core.Utils.ChunkedArray.add3(this.triangleBuffer, this.vertList[triInfo[t]], this.vertList[triInfo[t + 1]], this.vertList[triInfo[t + 2]]);
                        }
                    };
                    return MarchingCubesState;
                }());
            })(MarchingCubes = Geometry.MarchingCubes || (Geometry.MarchingCubes = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var MarchingCubes;
            (function (MarchingCubes) {
                var Index = /** @class */ (function () {
                    function Index(i, j, k) {
                        this.i = i | 0;
                        this.j = j | 0;
                        this.k = k | 0;
                    }
                    return Index;
                }());
                MarchingCubes.Index = Index;
                var IndexPair = /** @class */ (function () {
                    function IndexPair(a, b) {
                        this.a = a;
                        this.b = b;
                    }
                    return IndexPair;
                }());
                MarchingCubes.IndexPair = IndexPair;
                MarchingCubes.EdgesXY = [
                    [],
                    [0, 3],
                    [0, 1],
                    [1, 3],
                    [1, 2],
                    [0, 1, 1, 2, 2, 3, 0, 3],
                    [0, 2],
                    [2, 3],
                    [2, 3],
                    [0, 2],
                    [0, 1, 1, 2, 2, 3, 0, 3],
                    [1, 2],
                    [1, 3],
                    [0, 1],
                    [0, 3],
                    []
                ];
                MarchingCubes.EdgesXZ = [
                    [],
                    [0, 8],
                    [0, 9],
                    [9, 8],
                    [9, 4],
                    [0, 9, 9, 4, 4, 8, 0, 8],
                    [0, 4],
                    [4, 8],
                    [4, 8],
                    [0, 4],
                    [0, 9, 9, 4, 4, 8, 0, 8],
                    [9, 4],
                    [9, 8],
                    [0, 9],
                    [0, 8],
                    []
                ];
                MarchingCubes.EdgesYZ = [
                    [],
                    [3, 8],
                    [3, 11],
                    [11, 8],
                    [11, 7],
                    [3, 11, 11, 7, 7, 8, 3, 8],
                    [3, 7],
                    [7, 8],
                    [7, 8],
                    [3, 7],
                    [3, 11, 11, 7, 7, 8, 3, 8],
                    [11, 7],
                    [11, 8],
                    [3, 11],
                    [3, 8],
                    []
                ];
                MarchingCubes.CubeVertices = [
                    new Index(0, 0, 0),
                    new Index(1, 0, 0),
                    new Index(1, 1, 0),
                    new Index(0, 1, 0),
                    new Index(0, 0, 1),
                    new Index(1, 0, 1),
                    new Index(1, 1, 1),
                    new Index(0, 1, 1),
                ];
                MarchingCubes.CubeEdges = [
                    new IndexPair(MarchingCubes.CubeVertices[0], MarchingCubes.CubeVertices[1]),
                    new IndexPair(MarchingCubes.CubeVertices[1], MarchingCubes.CubeVertices[2]),
                    new IndexPair(MarchingCubes.CubeVertices[2], MarchingCubes.CubeVertices[3]),
                    new IndexPair(MarchingCubes.CubeVertices[3], MarchingCubes.CubeVertices[0]),
                    new IndexPair(MarchingCubes.CubeVertices[4], MarchingCubes.CubeVertices[5]),
                    new IndexPair(MarchingCubes.CubeVertices[5], MarchingCubes.CubeVertices[6]),
                    new IndexPair(MarchingCubes.CubeVertices[6], MarchingCubes.CubeVertices[7]),
                    new IndexPair(MarchingCubes.CubeVertices[7], MarchingCubes.CubeVertices[4]),
                    new IndexPair(MarchingCubes.CubeVertices[0], MarchingCubes.CubeVertices[4]),
                    new IndexPair(MarchingCubes.CubeVertices[1], MarchingCubes.CubeVertices[5]),
                    new IndexPair(MarchingCubes.CubeVertices[2], MarchingCubes.CubeVertices[6]),
                    new IndexPair(MarchingCubes.CubeVertices[3], MarchingCubes.CubeVertices[7]),
                ];
                MarchingCubes.EdgeIdInfo = [
                    { i: 0, j: 0, k: 0, e: 0 },
                    { i: 1, j: 0, k: 0, e: 1 },
                    { i: 0, j: 1, k: 0, e: 0 },
                    { i: 0, j: 0, k: 0, e: 1 },
                    { i: 0, j: 0, k: 1, e: 0 },
                    { i: 1, j: 0, k: 1, e: 1 },
                    { i: 0, j: 1, k: 1, e: 0 },
                    { i: 0, j: 0, k: 1, e: 1 },
                    { i: 0, j: 0, k: 0, e: 2 },
                    { i: 1, j: 0, k: 0, e: 2 },
                    { i: 1, j: 1, k: 0, e: 2 },
                    { i: 0, j: 1, k: 0, e: 2 }
                ];
                // export var EdgeIdInfo = [
                //     { i: 0, j: 0, k: 0, e: 0 },
                //     { i: 1, j: 0, k: 0, e: 1 },
                //     { i: 0, j: 1, k: 0, e: 0 },
                //     { i: 0, j: 0, k: 0, e: 1 },
                //     { i: 0, j: 0, k: 0, e: 0 },
                //     { i: 1, j: 0, k: 0, e: 1 },
                //     { i: 0, j: 1, k: 0, e: 0 },
                //     { i: 0, j: 0, k: 0, e: 1 },
                //     { i: 0, j: 0, k: 0, e: 0 },
                //     { i: 1, j: 0, k: 0, e: 1 },
                //     { i: 0, j: 1, k: 0, e: 0 },
                //     { i: 0, j: 0, k: 0, e: 1 },
                // ];
                // Tables EdgeTable and TriTable taken from http://paulbourke.net/geometry/polygonise/
                MarchingCubes.EdgeTable = [
                    0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
                    0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
                    0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
                    0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
                    0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
                    0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
                    0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
                    0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
                    0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
                    0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
                    0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
                    0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
                    0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
                    0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
                    0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
                    0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
                    0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
                    0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
                    0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
                    0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
                    0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
                    0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
                    0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
                    0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
                    0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
                    0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
                    0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
                    0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
                    0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
                    0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
                    0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
                    0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
                ];
                MarchingCubes.TriTable = [
                    [],
                    [0, 8, 3],
                    [0, 1, 9],
                    [1, 8, 3, 9, 8, 1],
                    [1, 2, 10],
                    [0, 8, 3, 1, 2, 10],
                    [9, 2, 10, 0, 2, 9],
                    [2, 8, 3, 2, 10, 8, 10, 9, 8],
                    [3, 11, 2],
                    [0, 11, 2, 8, 11, 0],
                    [1, 9, 0, 2, 3, 11],
                    [1, 11, 2, 1, 9, 11, 9, 8, 11],
                    [3, 10, 1, 11, 10, 3],
                    [0, 10, 1, 0, 8, 10, 8, 11, 10],
                    [3, 9, 0, 3, 11, 9, 11, 10, 9],
                    [9, 8, 10, 10, 8, 11],
                    [4, 7, 8],
                    [4, 3, 0, 7, 3, 4],
                    [0, 1, 9, 8, 4, 7],
                    [4, 1, 9, 4, 7, 1, 7, 3, 1],
                    [1, 2, 10, 8, 4, 7],
                    [3, 4, 7, 3, 0, 4, 1, 2, 10],
                    [9, 2, 10, 9, 0, 2, 8, 4, 7],
                    [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4],
                    [8, 4, 7, 3, 11, 2],
                    [11, 4, 7, 11, 2, 4, 2, 0, 4],
                    [9, 0, 1, 8, 4, 7, 2, 3, 11],
                    [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1],
                    [3, 10, 1, 3, 11, 10, 7, 8, 4],
                    [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4],
                    [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3],
                    [4, 7, 11, 4, 11, 9, 9, 11, 10],
                    [9, 5, 4],
                    [9, 5, 4, 0, 8, 3],
                    [0, 5, 4, 1, 5, 0],
                    [8, 5, 4, 8, 3, 5, 3, 1, 5],
                    [1, 2, 10, 9, 5, 4],
                    [3, 0, 8, 1, 2, 10, 4, 9, 5],
                    [5, 2, 10, 5, 4, 2, 4, 0, 2],
                    [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8],
                    [9, 5, 4, 2, 3, 11],
                    [0, 11, 2, 0, 8, 11, 4, 9, 5],
                    [0, 5, 4, 0, 1, 5, 2, 3, 11],
                    [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5],
                    [10, 3, 11, 10, 1, 3, 9, 5, 4],
                    [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10],
                    [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3],
                    [5, 4, 8, 5, 8, 10, 10, 8, 11],
                    [9, 7, 8, 5, 7, 9],
                    [9, 3, 0, 9, 5, 3, 5, 7, 3],
                    [0, 7, 8, 0, 1, 7, 1, 5, 7],
                    [1, 5, 3, 3, 5, 7],
                    [9, 7, 8, 9, 5, 7, 10, 1, 2],
                    [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3],
                    [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2],
                    [2, 10, 5, 2, 5, 3, 3, 5, 7],
                    [7, 9, 5, 7, 8, 9, 3, 11, 2],
                    [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11],
                    [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7],
                    [11, 2, 1, 11, 1, 7, 7, 1, 5],
                    [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11],
                    [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0],
                    [11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0],
                    [11, 10, 5, 7, 11, 5],
                    [10, 6, 5],
                    [0, 8, 3, 5, 10, 6],
                    [9, 0, 1, 5, 10, 6],
                    [1, 8, 3, 1, 9, 8, 5, 10, 6],
                    [1, 6, 5, 2, 6, 1],
                    [1, 6, 5, 1, 2, 6, 3, 0, 8],
                    [9, 6, 5, 9, 0, 6, 0, 2, 6],
                    [5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8],
                    [2, 3, 11, 10, 6, 5],
                    [11, 0, 8, 11, 2, 0, 10, 6, 5],
                    [0, 1, 9, 2, 3, 11, 5, 10, 6],
                    [5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11],
                    [6, 3, 11, 6, 5, 3, 5, 1, 3],
                    [0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6],
                    [3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9],
                    [6, 5, 9, 6, 9, 11, 11, 9, 8],
                    [5, 10, 6, 4, 7, 8],
                    [4, 3, 0, 4, 7, 3, 6, 5, 10],
                    [1, 9, 0, 5, 10, 6, 8, 4, 7],
                    [10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4],
                    [6, 1, 2, 6, 5, 1, 4, 7, 8],
                    [1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7],
                    [8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6],
                    [7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9],
                    [3, 11, 2, 7, 8, 4, 10, 6, 5],
                    [5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11],
                    [0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6],
                    [9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6],
                    [8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6],
                    [5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11],
                    [0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7],
                    [6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9],
                    [10, 4, 9, 6, 4, 10],
                    [4, 10, 6, 4, 9, 10, 0, 8, 3],
                    [10, 0, 1, 10, 6, 0, 6, 4, 0],
                    [8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10],
                    [1, 4, 9, 1, 2, 4, 2, 6, 4],
                    [3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4],
                    [0, 2, 4, 4, 2, 6],
                    [8, 3, 2, 8, 2, 4, 4, 2, 6],
                    [10, 4, 9, 10, 6, 4, 11, 2, 3],
                    [0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6],
                    [3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10],
                    [6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1],
                    [9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3],
                    [8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1],
                    [3, 11, 6, 3, 6, 0, 0, 6, 4],
                    [6, 4, 8, 11, 6, 8],
                    [7, 10, 6, 7, 8, 10, 8, 9, 10],
                    [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10],
                    [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0],
                    [10, 6, 7, 10, 7, 1, 1, 7, 3],
                    [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7],
                    [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9],
                    [7, 8, 0, 7, 0, 6, 6, 0, 2],
                    [7, 3, 2, 6, 7, 2],
                    [2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7],
                    [2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7],
                    [1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11],
                    [11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1],
                    [8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6],
                    [0, 9, 1, 11, 6, 7],
                    [7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0],
                    [7, 11, 6],
                    [7, 6, 11],
                    [3, 0, 8, 11, 7, 6],
                    [0, 1, 9, 11, 7, 6],
                    [8, 1, 9, 8, 3, 1, 11, 7, 6],
                    [10, 1, 2, 6, 11, 7],
                    [1, 2, 10, 3, 0, 8, 6, 11, 7],
                    [2, 9, 0, 2, 10, 9, 6, 11, 7],
                    [6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8],
                    [7, 2, 3, 6, 2, 7],
                    [7, 0, 8, 7, 6, 0, 6, 2, 0],
                    [2, 7, 6, 2, 3, 7, 0, 1, 9],
                    [1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6],
                    [10, 7, 6, 10, 1, 7, 1, 3, 7],
                    [10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8],
                    [0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7],
                    [7, 6, 10, 7, 10, 8, 8, 10, 9],
                    [6, 8, 4, 11, 8, 6],
                    [3, 6, 11, 3, 0, 6, 0, 4, 6],
                    [8, 6, 11, 8, 4, 6, 9, 0, 1],
                    [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6],
                    [6, 8, 4, 6, 11, 8, 2, 10, 1],
                    [1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6],
                    [4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9],
                    [10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3],
                    [8, 2, 3, 8, 4, 2, 4, 6, 2],
                    [0, 4, 2, 4, 6, 2],
                    [1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8],
                    [1, 9, 4, 1, 4, 2, 2, 4, 6],
                    [8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1],
                    [10, 1, 0, 10, 0, 6, 6, 0, 4],
                    [4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3],
                    [10, 9, 4, 6, 10, 4],
                    [4, 9, 5, 7, 6, 11],
                    [0, 8, 3, 4, 9, 5, 11, 7, 6],
                    [5, 0, 1, 5, 4, 0, 7, 6, 11],
                    [11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5],
                    [9, 5, 4, 10, 1, 2, 7, 6, 11],
                    [6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5],
                    [7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2],
                    [3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6],
                    [7, 2, 3, 7, 6, 2, 5, 4, 9],
                    [9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7],
                    [3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0],
                    [6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8],
                    [9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7],
                    [1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4],
                    [4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10],
                    [7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10],
                    [6, 9, 5, 6, 11, 9, 11, 8, 9],
                    [3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5],
                    [0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11],
                    [6, 11, 3, 6, 3, 5, 5, 3, 1],
                    [1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6],
                    [0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10],
                    [11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5],
                    [6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3],
                    [5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2],
                    [9, 5, 6, 9, 6, 0, 0, 6, 2],
                    [1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8],
                    [1, 5, 6, 2, 1, 6],
                    [1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6],
                    [10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0],
                    [0, 3, 8, 5, 6, 10],
                    [10, 5, 6],
                    [11, 5, 10, 7, 5, 11],
                    [11, 5, 10, 11, 7, 5, 8, 3, 0],
                    [5, 11, 7, 5, 10, 11, 1, 9, 0],
                    [10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1],
                    [11, 1, 2, 11, 7, 1, 7, 5, 1],
                    [0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11],
                    [9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7],
                    [7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2],
                    [2, 5, 10, 2, 3, 5, 3, 7, 5],
                    [8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5],
                    [9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2],
                    [9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2],
                    [1, 3, 5, 3, 7, 5],
                    [0, 8, 7, 0, 7, 1, 1, 7, 5],
                    [9, 0, 3, 9, 3, 5, 5, 3, 7],
                    [9, 8, 7, 5, 9, 7],
                    [5, 8, 4, 5, 10, 8, 10, 11, 8],
                    [5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0],
                    [0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5],
                    [10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4],
                    [2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8],
                    [0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11],
                    [0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5],
                    [9, 4, 5, 2, 11, 3],
                    [2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4],
                    [5, 10, 2, 5, 2, 4, 4, 2, 0],
                    [3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9],
                    [5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2],
                    [8, 4, 5, 8, 5, 3, 3, 5, 1],
                    [0, 4, 5, 1, 0, 5],
                    [8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5],
                    [9, 4, 5],
                    [4, 11, 7, 4, 9, 11, 9, 10, 11],
                    [0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11],
                    [1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11],
                    [3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4],
                    [4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2],
                    [9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3],
                    [11, 7, 4, 11, 4, 2, 2, 4, 0],
                    [11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4],
                    [2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9],
                    [9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7],
                    [3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10],
                    [1, 10, 2, 8, 7, 4],
                    [4, 9, 1, 4, 1, 7, 7, 1, 3],
                    [4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1],
                    [4, 0, 3, 7, 4, 3],
                    [4, 8, 7],
                    [9, 10, 8, 10, 11, 8],
                    [3, 0, 9, 3, 9, 11, 11, 9, 10],
                    [0, 1, 10, 0, 10, 8, 8, 10, 11],
                    [3, 1, 10, 11, 3, 10],
                    [1, 2, 11, 1, 11, 9, 9, 11, 8],
                    [3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9],
                    [0, 2, 11, 8, 0, 11],
                    [3, 2, 11],
                    [2, 3, 8, 2, 8, 10, 10, 8, 9],
                    [9, 10, 2, 0, 9, 2],
                    [2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8],
                    [1, 10, 2],
                    [1, 3, 8, 9, 1, 8],
                    [0, 9, 1],
                    [0, 3, 8],
                    []
                ];
            })(MarchingCubes = Geometry.MarchingCubes || (Geometry.MarchingCubes = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Geometry;
        (function (Geometry) {
            var MolecularSurface;
            (function (MolecularSurface) {
                "use strict";
                var MolecularIsoSurfaceParametersWrapper = /** @class */ (function () {
                    function MolecularIsoSurfaceParametersWrapper(params) {
                        Core.Utils.extend(this, params, {
                            exactBoundary: false,
                            boundaryDelta: { dx: 1.5, dy: 1.5, dz: 1.5 },
                            probeRadius: 1.4,
                            atomRadii: function () { return 1.0; },
                            density: 1.1,
                            interactive: false,
                            smoothingIterations: 1
                        });
                        if (this.exactBoundary)
                            this.boundaryDelta = { dx: 0, dy: 0, dz: 0 };
                        if (this.density < 0.05)
                            this.density = 0.05;
                    }
                    return MolecularIsoSurfaceParametersWrapper;
                }());
                var MolecularIsoFieldComputation = /** @class */ (function () {
                    function MolecularIsoFieldComputation(inputParameters, ctx) {
                        this.inputParameters = inputParameters;
                        this.ctx = ctx;
                        this.minX = Number.MAX_VALUE;
                        this.minY = Number.MAX_VALUE;
                        this.minZ = Number.MAX_VALUE;
                        this.maxX = -Number.MAX_VALUE;
                        this.maxY = -Number.MAX_VALUE;
                        this.maxZ = -Number.MAX_VALUE;
                        this.nX = 0;
                        this.nY = 0;
                        this.nZ = 0;
                        this.dX = 0.1;
                        this.dY = 0.1;
                        this.dZ = 0.1;
                        this.field = new Float32Array(0);
                        this.distanceField = new Float32Array(0);
                        this.proximityMap = new Int32Array(0);
                        this.minIndex = { i: 0, j: 0, k: 0 };
                        this.maxIndex = { i: 0, j: 0, k: 0 };
                        this.parameters = new MolecularIsoSurfaceParametersWrapper(inputParameters.parameters);
                        var positions = inputParameters.positions;
                        this.x = positions.x;
                        this.y = positions.y;
                        this.z = positions.z;
                        this.atomIndices = inputParameters.atomIndices;
                        // make the atoms artificially bigger for low resolution surfaces
                        if (this.parameters.density >= 0.99) {
                            // so that the number is float and not int32 internally 
                            this.vdwScaleFactor = 1.000000001;
                        }
                        else {
                            this.vdwScaleFactor = 1 + (1 - this.parameters.density * this.parameters.density);
                        }
                    }
                    MolecularIsoFieldComputation.prototype.findBounds = function () {
                        for (var _i = 0, _a = this.atomIndices; _i < _a.length; _i++) {
                            var aI = _a[_i];
                            var r = this.parameters.exactBoundary ? 0 : this.vdwScaleFactor * this.parameters.atomRadius(aI) + this.parameters.probeRadius, xx = this.x[aI], yy = this.y[aI], zz = this.z[aI];
                            if (r < 0)
                                continue;
                            this.minX = Math.min(this.minX, xx - r);
                            this.minY = Math.min(this.minY, yy - r);
                            this.minZ = Math.min(this.minZ, zz - r);
                            this.maxX = Math.max(this.maxX, xx + r);
                            this.maxY = Math.max(this.maxY, yy + r);
                            this.maxZ = Math.max(this.maxZ, zz + r);
                        }
                        if (this.minX === Number.MAX_VALUE) {
                            this.minX = this.minY = this.minZ = -1;
                            this.maxX = this.maxY = this.maxZ = 1;
                        }
                        this.minX -= this.parameters.boundaryDelta.dx;
                        this.minY -= this.parameters.boundaryDelta.dy;
                        this.minZ -= this.parameters.boundaryDelta.dz;
                        this.maxX += this.parameters.boundaryDelta.dx;
                        this.maxY += this.parameters.boundaryDelta.dy;
                        this.maxZ += this.parameters.boundaryDelta.dz;
                        this.nX = Math.floor((this.maxX - this.minX) * this.parameters.density);
                        this.nY = Math.floor((this.maxY - this.minY) * this.parameters.density);
                        this.nZ = Math.floor((this.maxZ - this.minZ) * this.parameters.density);
                        this.nX = Math.min(this.nX, 333);
                        this.nY = Math.min(this.nY, 333);
                        this.nZ = Math.min(this.nZ, 333);
                        this.dX = (this.maxX - this.minX) / (this.nX - 1);
                        this.dY = (this.maxY - this.minY) / (this.nY - 1);
                        this.dZ = (this.maxZ - this.minZ) / (this.nZ - 1);
                    };
                    MolecularIsoFieldComputation.prototype.initData = function () {
                        var len = this.nX * this.nY * this.nZ;
                        this.field = new Float32Array(len);
                        this.distanceField = new Float32Array(len);
                        this.proximityMap = new Int32Array(len);
                        var mv = Number.POSITIVE_INFINITY;
                        for (var j = 0, _b = this.proximityMap.length; j < _b; j++) {
                            this.distanceField[j] = mv;
                            this.proximityMap[j] = -1;
                        }
                    };
                    MolecularIsoFieldComputation.prototype.updateMinIndex = function (x, y, z) {
                        this.minIndex.i = Math.max((Math.floor((x - this.minX) / this.dX)) | 0, 0);
                        this.minIndex.j = Math.max((Math.floor((y - this.minY) / this.dY)) | 0, 0);
                        this.minIndex.k = Math.max((Math.floor((z - this.minZ) / this.dZ)) | 0, 0);
                    };
                    MolecularIsoFieldComputation.prototype.updateMaxIndex = function (x, y, z) {
                        this.maxIndex.i = Math.min((Math.ceil((x - this.minX) / this.dX)) | 0, this.nX);
                        this.maxIndex.j = Math.min((Math.ceil((y - this.minY) / this.dY)) | 0, this.nY);
                        this.maxIndex.k = Math.min((Math.ceil((z - this.minZ) / this.dZ)) | 0, this.nZ);
                    };
                    MolecularIsoFieldComputation.prototype.addBall = function (aI, strength) {
                        var strSq = strength * strength;
                        var cx = this.x[aI], cy = this.y[aI], cz = this.z[aI];
                        this.updateMinIndex(cx - strength, cy - strength, cz - strength);
                        this.updateMaxIndex(cx + strength, cy + strength, cz + strength);
                        var mini = this.minIndex.i, minj = this.minIndex.j, mink = this.minIndex.k;
                        var maxi = this.maxIndex.i, maxj = this.maxIndex.j, maxk = this.maxIndex.k;
                        cx = this.minX - cx;
                        cy = this.minY - cy;
                        cz = this.minZ - cz;
                        for (var k = mink; k < maxk; k++) {
                            var tZ = cz + k * this.dZ, zz = tZ * tZ, oZ = k * this.nY;
                            for (var j = minj; j < maxj; j++) {
                                var tY = cy + j * this.dY, yy = zz + tY * tY, oY = this.nX * (oZ + j);
                                for (var i = mini; i < maxi; i++) {
                                    var tX = cx + i * this.dX, xx = yy + tX * tX, offset = oY + i;
                                    var v = strSq / (0.000001 + xx) - 1;
                                    if (xx < this.distanceField[offset]) {
                                        this.proximityMap[offset] = aI;
                                        this.distanceField[offset] = xx;
                                    }
                                    if (v > 0) {
                                        this.field[offset] += v;
                                    }
                                }
                            }
                        }
                    };
                    MolecularIsoFieldComputation.prototype.processChunks = function () {
                        return __awaiter(this, void 0, void 0, function () {
                            var chunkSize, started, currentAtom, _b, aI, r, t;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        chunkSize = 10000;
                                        started = Core.Utils.PerformanceMonitor.currentTime();
                                        return [4 /*yield*/, this.ctx.updateProgress('Creating field...', true)];
                                    case 1:
                                        _a.sent();
                                        currentAtom = 0, _b = this.atomIndices.length;
                                        _a.label = 2;
                                    case 2:
                                        if (!(currentAtom < _b)) return [3 /*break*/, 5];
                                        aI = this.atomIndices[currentAtom];
                                        r = this.vdwScaleFactor * this.parameters.atomRadius(aI) + this.parameters.probeRadius;
                                        if (r >= 0) {
                                            this.addBall(aI, r);
                                        }
                                        if (!((currentAtom + 1) % chunkSize === 0)) return [3 /*break*/, 4];
                                        t = Core.Utils.PerformanceMonitor.currentTime();
                                        if (!(t - started > Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 4];
                                        started = t;
                                        return [4 /*yield*/, this.ctx.updateProgress('Creating field...', true, currentAtom, _b)];
                                    case 3:
                                        _a.sent();
                                        _a.label = 4;
                                    case 4:
                                        currentAtom++;
                                        return [3 /*break*/, 2];
                                    case 5: return [2 /*return*/];
                                }
                            });
                        });
                    };
                    MolecularIsoFieldComputation.prototype.finish = function () {
                        var t = Geometry.LinearAlgebra.Matrix4.zero();
                        Geometry.LinearAlgebra.Matrix4.fromTranslation(t, [this.minX, this.minY, this.minZ]);
                        t[0] = this.dX;
                        t[5] = this.dY;
                        t[10] = this.dZ;
                        var ret = {
                            data: {
                                scalarField: new Core.Formats.Density.Field3DZYX(this.field, [this.nX, this.nY, this.nZ]),
                                annotationField: this.parameters.interactive ? new Core.Formats.Density.Field3DZYX(this.proximityMap, [this.nX, this.nY, this.nZ]) : void 0,
                                isoLevel: 0.05
                            },
                            bottomLeft: Geometry.LinearAlgebra.Vector3.fromValues(this.minX, this.minY, this.minZ),
                            topRight: Geometry.LinearAlgebra.Vector3.fromValues(this.maxX, this.maxY, this.maxZ),
                            transform: t,
                            inputParameters: this.inputParameters,
                            parameters: this.parameters
                        };
                        // help the gc
                        this.distanceField = null;
                        this.proximityMap = null;
                        return ret;
                    };
                    MolecularIsoFieldComputation.prototype.run = function () {
                        return __awaiter(this, void 0, void 0, function () {
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, this.ctx.updateProgress('Initializing...')];
                                    case 1:
                                        _a.sent();
                                        this.findBounds();
                                        this.initData();
                                        return [4 /*yield*/, this.processChunks()];
                                    case 2:
                                        _a.sent();
                                        return [4 /*yield*/, this.ctx.updateProgress('Finalizing...', void 0, this.atomIndices.length, this.atomIndices.length)];
                                    case 3:
                                        _a.sent();
                                        return [2 /*return*/, this.finish()];
                                }
                            });
                        });
                    };
                    return MolecularIsoFieldComputation;
                }());
                function createMolecularIsoFieldAsync(parameters) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var field;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    field = new MolecularIsoFieldComputation(parameters, ctx);
                                    return [4 /*yield*/, field.run()];
                                case 1: return [2 /*return*/, _a.sent()];
                            }
                        });
                    }); });
                }
                MolecularSurface.createMolecularIsoFieldAsync = createMolecularIsoFieldAsync;
                function computeMolecularSurfaceAsync(parameters) {
                    var _this = this;
                    return Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var field, surface, smoothing, smoothingVertexWeight;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, createMolecularIsoFieldAsync(parameters).run(ctx)];
                                case 1:
                                    field = _a.sent();
                                    return [4 /*yield*/, Geometry.MarchingCubes.compute(field.data).run(ctx)];
                                case 2:
                                    surface = _a.sent();
                                    return [4 /*yield*/, Geometry.Surface.transform(surface, field.transform).run(ctx)];
                                case 3:
                                    surface = _a.sent();
                                    smoothing = (parameters.parameters && parameters.parameters.smoothingIterations) || 1;
                                    smoothingVertexWeight = 1.0;
                                    // low density results in very low detail and large distance between vertices.
                                    // Applying uniform laplacian smmoth to such surfaces makes the surface a lot smaller 
                                    // in each iteration. 
                                    // To reduce this behaviour, the weight of the "central" vertex is increased
                                    // for low desities to better preserve the shape of the surface.
                                    if (parameters.parameters && parameters.parameters.density < 1) {
                                        smoothingVertexWeight = 2 / parameters.parameters.density;
                                    }
                                    return [4 /*yield*/, Geometry.Surface.laplacianSmooth(surface, smoothing, smoothingVertexWeight).run(ctx)];
                                case 4:
                                    surface = _a.sent();
                                    return [2 /*return*/, { surface: surface, usedParameters: field.parameters }];
                            }
                        });
                    }); });
                }
                MolecularSurface.computeMolecularSurfaceAsync = computeMolecularSurfaceAsync;
            })(MolecularSurface = Geometry.MolecularSurface || (Geometry.MolecularSurface = {}));
        })(Geometry = Core.Geometry || (Core.Geometry = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            "use strict";
            var DataTable = Core.Utils.DataTable;
            var ComponentBondInfoEntry = /** @class */ (function () {
                function ComponentBondInfoEntry(id) {
                    this.id = id;
                    this.map = Core.Utils.FastMap.create();
                }
                ComponentBondInfoEntry.prototype.add = function (a, b, order, swap) {
                    if (swap === void 0) { swap = true; }
                    var e = this.map.get(a);
                    if (e !== void 0) {
                        var f = e.get(b);
                        if (f === void 0) {
                            e.set(b, order);
                        }
                    }
                    else {
                        var map = Core.Utils.FastMap.create();
                        map.set(b, order);
                        this.map.set(a, map);
                    }
                    if (swap)
                        this.add(b, a, order, false);
                };
                return ComponentBondInfoEntry;
            }());
            Structure.ComponentBondInfoEntry = ComponentBondInfoEntry;
            var ComponentBondInfo = /** @class */ (function () {
                function ComponentBondInfo() {
                    this.entries = Core.Utils.FastMap.create();
                }
                ComponentBondInfo.prototype.newEntry = function (id) {
                    var e = new ComponentBondInfoEntry(id);
                    this.entries.set(id, e);
                    return e;
                };
                return ComponentBondInfo;
            }());
            Structure.ComponentBondInfo = ComponentBondInfo;
            /**
             * Identifier for a reside that is a part of the polymer.
             */
            var PolyResidueIdentifier = /** @class */ (function () {
                function PolyResidueIdentifier(asymId, seqNumber, insCode) {
                    this.asymId = asymId;
                    this.seqNumber = seqNumber;
                    this.insCode = insCode;
                }
                PolyResidueIdentifier.areEqual = function (a, index, bAsymId, bSeqNumber, bInsCode) {
                    return a.asymId === bAsymId[index]
                        && a.seqNumber === bSeqNumber[index]
                        && a.insCode === bInsCode[index];
                };
                PolyResidueIdentifier.compare = function (a, b) {
                    if (a.asymId === b.asymId) {
                        if (a.seqNumber === b.seqNumber) {
                            if (a.insCode === b.insCode)
                                return 0;
                            if (a.insCode === void 0)
                                return -1;
                            if (b.insCode === void 0)
                                return 1;
                            return a.insCode < b.insCode ? -1 : 1;
                        }
                        return a.seqNumber < b.seqNumber ? -1 : 1;
                    }
                    return a.asymId < b.asymId ? -1 : 1;
                };
                PolyResidueIdentifier.compareResidue = function (a, index, bAsymId, bSeqNumber, bInsCode) {
                    if (a.asymId === bAsymId[index]) {
                        if (a.seqNumber === bSeqNumber[index]) {
                            if (a.insCode === bInsCode[index])
                                return 0;
                            if (a.insCode === void 0)
                                return -1;
                            if (bInsCode[index] === void 0)
                                return 1;
                            return a.insCode < bInsCode[index] ? -1 : 1;
                        }
                        return a.seqNumber < bSeqNumber[index] ? -1 : 1;
                    }
                    return a.asymId < bAsymId[index] ? -1 : 1;
                };
                return PolyResidueIdentifier;
            }());
            Structure.PolyResidueIdentifier = PolyResidueIdentifier;
            var SecondaryStructureElement = /** @class */ (function () {
                function SecondaryStructureElement(type, startResidueId, endResidueId, info) {
                    if (info === void 0) { info = {}; }
                    this.type = type;
                    this.startResidueId = startResidueId;
                    this.endResidueId = endResidueId;
                    this.info = info;
                    this.startResidueIndex = -1;
                    this.endResidueIndex = -1;
                }
                Object.defineProperty(SecondaryStructureElement.prototype, "length", {
                    get: function () {
                        return this.endResidueIndex - this.startResidueIndex;
                    },
                    enumerable: true,
                    configurable: true
                });
                return SecondaryStructureElement;
            }());
            Structure.SecondaryStructureElement = SecondaryStructureElement;
            var SymmetryInfo = /** @class */ (function () {
                function SymmetryInfo(spacegroupName, cellSize, cellAngles, toFracTransform, isNonStandardCrytalFrame) {
                    this.spacegroupName = spacegroupName;
                    this.cellSize = cellSize;
                    this.cellAngles = cellAngles;
                    this.toFracTransform = toFracTransform;
                    this.isNonStandardCrytalFrame = isNonStandardCrytalFrame;
                }
                return SymmetryInfo;
            }());
            Structure.SymmetryInfo = SymmetryInfo;
            /**
             * Wraps _struct_conn mmCIF category.
             */
            var StructConn = /** @class */ (function () {
                function StructConn(entries) {
                    this.entries = entries;
                    this._residuePairIndex = void 0;
                    this._atomIndex = void 0;
                }
                StructConn._resKey = function (rA, rB) {
                    if (rA < rB)
                        return rA + "-" + rB;
                    return rB + "-" + rA;
                };
                StructConn.prototype.getResiduePairIndex = function () {
                    if (this._residuePairIndex)
                        return this._residuePairIndex;
                    this._residuePairIndex = Core.Utils.FastMap.create();
                    for (var _i = 0, _a = this.entries; _i < _a.length; _i++) {
                        var e = _a[_i];
                        var ps = e.partners;
                        var l = ps.length;
                        for (var i = 0; i < l - 1; i++) {
                            for (var j = i + i; j < l; j++) {
                                var key = StructConn._resKey(ps[i].residueIndex, ps[j].residueIndex);
                                if (this._residuePairIndex.has(key)) {
                                    this._residuePairIndex.get(key).push(e);
                                }
                                else {
                                    this._residuePairIndex.set(key, [e]);
                                }
                            }
                        }
                    }
                    return this._residuePairIndex;
                };
                StructConn.prototype.getAtomIndex = function () {
                    if (this._atomIndex)
                        return this._atomIndex;
                    this._atomIndex = Core.Utils.FastMap.create();
                    for (var _i = 0, _a = this.entries; _i < _a.length; _i++) {
                        var e = _a[_i];
                        for (var _c = 0, _d = e.partners; _c < _d.length; _c++) {
                            var p = _d[_c];
                            var key = p.atomIndex;
                            if (this._atomIndex.has(key)) {
                                this._atomIndex.get(key).push(e);
                            }
                            else {
                                this._atomIndex.set(key, [e]);
                            }
                        }
                    }
                    return this._atomIndex;
                };
                StructConn.prototype.getResidueEntries = function (residueAIndex, residueBIndex) {
                    return this.getResiduePairIndex().get(StructConn._resKey(residueAIndex, residueBIndex)) || StructConn._emptyEntry;
                };
                StructConn.prototype.getAtomEntries = function (atomIndex) {
                    return this.getAtomIndex().get(atomIndex) || StructConn._emptyEntry;
                };
                StructConn._emptyEntry = [];
                return StructConn;
            }());
            Structure.StructConn = StructConn;
            /**
             * Wraps an assembly operator.
             */
            var AssemblyOperator = /** @class */ (function () {
                function AssemblyOperator(id, name, operator) {
                    this.id = id;
                    this.name = name;
                    this.operator = operator;
                }
                return AssemblyOperator;
            }());
            Structure.AssemblyOperator = AssemblyOperator;
            /**
             * Wraps a single assembly gen entry.
             */
            var AssemblyGenEntry = /** @class */ (function () {
                function AssemblyGenEntry(operators, asymIds) {
                    this.operators = operators;
                    this.asymIds = asymIds;
                }
                return AssemblyGenEntry;
            }());
            Structure.AssemblyGenEntry = AssemblyGenEntry;
            /**
             * Wraps an assembly generation template.
             */
            var AssemblyGen = /** @class */ (function () {
                function AssemblyGen(name) {
                    this.name = name;
                    this.gens = [];
                }
                return AssemblyGen;
            }());
            Structure.AssemblyGen = AssemblyGen;
            /**
             * Information about the assemblies.
             */
            var AssemblyInfo = /** @class */ (function () {
                function AssemblyInfo(operators, assemblies) {
                    this.operators = operators;
                    this.assemblies = assemblies;
                }
                return AssemblyInfo;
            }());
            Structure.AssemblyInfo = AssemblyInfo;
            /**
             * Default Builders
             */
            var Tables;
            (function (Tables) {
                var int32 = DataTable.typedColumn(Int32Array);
                var float32 = DataTable.typedColumn(Float32Array);
                var str = DataTable.stringColumn;
                var nullStr = DataTable.stringNullColumn;
                Tables.Positions = {
                    x: float32,
                    y: float32,
                    z: float32
                };
                Tables.Atoms = {
                    id: int32,
                    altLoc: str,
                    residueIndex: int32,
                    chainIndex: int32,
                    entityIndex: int32,
                    name: str,
                    elementSymbol: str,
                    occupancy: float32,
                    tempFactor: float32,
                    authName: str,
                    rowIndex: int32
                };
                Tables.Residues = {
                    name: str,
                    seqNumber: int32,
                    asymId: str,
                    authName: str,
                    authSeqNumber: int32,
                    authAsymId: str,
                    insCode: nullStr,
                    entityId: str,
                    isHet: DataTable.typedColumn(Int8Array),
                    atomStartIndex: int32,
                    atomEndIndex: int32,
                    chainIndex: int32,
                    entityIndex: int32,
                    secondaryStructureIndex: int32
                };
                Tables.Chains = {
                    asymId: str,
                    entityId: str,
                    authAsymId: str,
                    atomStartIndex: int32,
                    atomEndIndex: int32,
                    residueStartIndex: int32,
                    residueEndIndex: int32,
                    entityIndex: int32,
                    sourceChainIndex: void 0,
                    operatorIndex: void 0
                };
                Tables.Entities = {
                    entityId: str,
                    type: DataTable.customColumn(),
                    atomStartIndex: int32,
                    atomEndIndex: int32,
                    residueStartIndex: int32,
                    residueEndIndex: int32,
                    chainStartIndex: int32,
                    chainEndIndex: int32
                };
                Tables.Bonds = {
                    atomAIndex: int32,
                    atomBIndex: int32,
                    type: DataTable.typedColumn(Int8Array)
                };
                Tables.ModifiedResidues = {
                    asymId: str,
                    seqNumber: int32,
                    insCode: nullStr,
                    parent: str,
                    details: nullStr
                };
            })(Tables = Structure.Tables || (Structure.Tables = {}));
            var Operator = /** @class */ (function () {
                function Operator(matrix, id, isIdentity) {
                    this.matrix = matrix;
                    this.id = id;
                    this.isIdentity = isIdentity;
                }
                Operator.prototype.apply = function (v) {
                    Core.Geometry.LinearAlgebra.Vector3.transformMat4(v, v, this.matrix);
                };
                Operator.applyToModelUnsafe = function (matrix, m) {
                    var v = Core.Geometry.LinearAlgebra.Vector3.zero();
                    var _a = m.positions, x = _a.x, y = _a.y, z = _a.z;
                    for (var i = 0, _b = m.positions.count; i < _b; i++) {
                        v[0] = x[i];
                        v[1] = y[i];
                        v[2] = z[i];
                        Core.Geometry.LinearAlgebra.Vector3.transformMat4(v, v, matrix);
                        x[i] = v[0];
                        y[i] = v[1];
                        z[i] = v[2];
                    }
                };
                return Operator;
            }());
            Structure.Operator = Operator;
            var Molecule;
            (function (Molecule) {
                function create(id, models, properties) {
                    if (properties === void 0) { properties = {}; }
                    return { id: id, models: models, properties: properties };
                }
                Molecule.create = create;
                var Model;
                (function (Model) {
                    function create(model) {
                        var ret = Core.Utils.extend({}, model);
                        var queryContext = void 0;
                        Object.defineProperty(ret, 'queryContext', { enumerable: true, configurable: false, get: function () {
                                if (queryContext)
                                    return queryContext;
                                queryContext = Structure.Query.Context.ofStructure(ret);
                                return queryContext;
                            } });
                        return ret;
                    }
                    Model.create = create;
                    var Source;
                    (function (Source) {
                        Source[Source["File"] = 0] = "File";
                        Source[Source["Computed"] = 1] = "Computed";
                    })(Source = Model.Source || (Model.Source = {}));
                    function withTransformedXYZ(model, ctx, transform) {
                        var _a = model.positions, x = _a.x, y = _a.y, z = _a.z;
                        var tAtoms = model.positions.getBuilder(model.positions.count).seal();
                        var tX = tAtoms.x, tY = tAtoms.y, tZ = tAtoms.z;
                        var t = Core.Geometry.LinearAlgebra.Vector3.zero();
                        for (var i = 0, _l = model.positions.count; i < _l; i++) {
                            transform(ctx, x[i], y[i], z[i], t);
                            tX[i] = t[0];
                            tY[i] = t[1];
                            tZ[i] = t[2];
                        }
                        return create({
                            id: model.id,
                            modelId: model.modelId,
                            data: model.data,
                            positions: tAtoms,
                            parent: model.parent,
                            source: model.source,
                            operators: model.operators
                        });
                    }
                    Model.withTransformedXYZ = withTransformedXYZ;
                })(Model = Molecule.Model || (Molecule.Model = {}));
            })(Molecule = Structure.Molecule || (Structure.Molecule = {}));
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            'use strict';
            function isBondTypeCovalent(t) {
                return t >= 0 /* Unknown */ && t <= 5 /* DisulfideBridge */;
            }
            Structure.isBondTypeCovalent = isBondTypeCovalent;
            // H,D,T are all mapped to H
            var __ElementIndex = { 'H': 0, 'h': 0, 'D': 0, 'd': 0, 'T': 0, 't': 0, 'He': 2, 'HE': 2, 'he': 2, 'Li': 3, 'LI': 3, 'li': 3, 'Be': 4, 'BE': 4, 'be': 4, 'B': 5, 'b': 5, 'C': 6, 'c': 6, 'N': 7, 'n': 7, 'O': 8, 'o': 8, 'F': 9, 'f': 9, 'Ne': 10, 'NE': 10, 'ne': 10, 'Na': 11, 'NA': 11, 'na': 11, 'Mg': 12, 'MG': 12, 'mg': 12, 'Al': 13, 'AL': 13, 'al': 13, 'Si': 14, 'SI': 14, 'si': 14, 'P': 15, 'p': 15, 'S': 16, 's': 16, 'Cl': 17, 'CL': 17, 'cl': 17, 'Ar': 18, 'AR': 18, 'ar': 18, 'K': 19, 'k': 19, 'Ca': 20, 'CA': 20, 'ca': 20, 'Sc': 21, 'SC': 21, 'sc': 21, 'Ti': 22, 'TI': 22, 'ti': 22, 'V': 23, 'v': 23, 'Cr': 24, 'CR': 24, 'cr': 24, 'Mn': 25, 'MN': 25, 'mn': 25, 'Fe': 26, 'FE': 26, 'fe': 26, 'Co': 27, 'CO': 27, 'co': 27, 'Ni': 28, 'NI': 28, 'ni': 28, 'Cu': 29, 'CU': 29, 'cu': 29, 'Zn': 30, 'ZN': 30, 'zn': 30, 'Ga': 31, 'GA': 31, 'ga': 31, 'Ge': 32, 'GE': 32, 'ge': 32, 'As': 33, 'AS': 33, 'as': 33, 'Se': 34, 'SE': 34, 'se': 34, 'Br': 35, 'BR': 35, 'br': 35, 'Kr': 36, 'KR': 36, 'kr': 36, 'Rb': 37, 'RB': 37, 'rb': 37, 'Sr': 38, 'SR': 38, 'sr': 38, 'Y': 39, 'y': 39, 'Zr': 40, 'ZR': 40, 'zr': 40, 'Nb': 41, 'NB': 41, 'nb': 41, 'Mo': 42, 'MO': 42, 'mo': 42, 'Tc': 43, 'TC': 43, 'tc': 43, 'Ru': 44, 'RU': 44, 'ru': 44, 'Rh': 45, 'RH': 45, 'rh': 45, 'Pd': 46, 'PD': 46, 'pd': 46, 'Ag': 47, 'AG': 47, 'ag': 47, 'Cd': 48, 'CD': 48, 'cd': 48, 'In': 49, 'IN': 49, 'in': 49, 'Sn': 50, 'SN': 50, 'sn': 50, 'Sb': 51, 'SB': 51, 'sb': 51, 'Te': 52, 'TE': 52, 'te': 52, 'I': 53, 'i': 53, 'Xe': 54, 'XE': 54, 'xe': 54, 'Cs': 55, 'CS': 55, 'cs': 55, 'Ba': 56, 'BA': 56, 'ba': 56, 'La': 57, 'LA': 57, 'la': 57, 'Ce': 58, 'CE': 58, 'ce': 58, 'Pr': 59, 'PR': 59, 'pr': 59, 'Nd': 60, 'ND': 60, 'nd': 60, 'Pm': 61, 'PM': 61, 'pm': 61, 'Sm': 62, 'SM': 62, 'sm': 62, 'Eu': 63, 'EU': 63, 'eu': 63, 'Gd': 64, 'GD': 64, 'gd': 64, 'Tb': 65, 'TB': 65, 'tb': 65, 'Dy': 66, 'DY': 66, 'dy': 66, 'Ho': 67, 'HO': 67, 'ho': 67, 'Er': 68, 'ER': 68, 'er': 68, 'Tm': 69, 'TM': 69, 'tm': 69, 'Yb': 70, 'YB': 70, 'yb': 70, 'Lu': 71, 'LU': 71, 'lu': 71, 'Hf': 72, 'HF': 72, 'hf': 72, 'Ta': 73, 'TA': 73, 'ta': 73, 'W': 74, 'w': 74, 'Re': 75, 'RE': 75, 're': 75, 'Os': 76, 'OS': 76, 'os': 76, 'Ir': 77, 'IR': 77, 'ir': 77, 'Pt': 78, 'PT': 78, 'pt': 78, 'Au': 79, 'AU': 79, 'au': 79, 'Hg': 80, 'HG': 80, 'hg': 80, 'Tl': 81, 'TL': 81, 'tl': 81, 'Pb': 82, 'PB': 82, 'pb': 82, 'Bi': 83, 'BI': 83, 'bi': 83, 'Po': 84, 'PO': 84, 'po': 84, 'At': 85, 'AT': 85, 'at': 85, 'Rn': 86, 'RN': 86, 'rn': 86, 'Fr': 87, 'FR': 87, 'fr': 87, 'Ra': 88, 'RA': 88, 'ra': 88, 'Ac': 89, 'AC': 89, 'ac': 89, 'Th': 90, 'TH': 90, 'th': 90, 'Pa': 91, 'PA': 91, 'pa': 91, 'U': 92, 'u': 92, 'Np': 93, 'NP': 93, 'np': 93, 'Pu': 94, 'PU': 94, 'pu': 94, 'Am': 95, 'AM': 95, 'am': 95, 'Cm': 96, 'CM': 96, 'cm': 96, 'Bk': 97, 'BK': 97, 'bk': 97, 'Cf': 98, 'CF': 98, 'cf': 98, 'Es': 99, 'ES': 99, 'es': 99, 'Fm': 100, 'FM': 100, 'fm': 100, 'Md': 101, 'MD': 101, 'md': 101, 'No': 102, 'NO': 102, 'no': 102, 'Lr': 103, 'LR': 103, 'lr': 103, 'Rf': 104, 'RF': 104, 'rf': 104, 'Db': 105, 'DB': 105, 'db': 105, 'Sg': 106, 'SG': 106, 'sg': 106, 'Bh': 107, 'BH': 107, 'bh': 107, 'Hs': 108, 'HS': 108, 'hs': 108, 'Mt': 109, 'MT': 109, 'mt': 109 };
            var __ElementBondThresholds = { 0: 1.42, 1: 1.42, 3: 2.7, 4: 2.7, 6: 1.75, 7: 1.6, 8: 1.52, 11: 2.7, 12: 2.7, 13: 2.7, 14: 1.9, 15: 1.9, 16: 1.9, 17: 1.8, 19: 2.7, 20: 2.7, 21: 2.7, 22: 2.7, 23: 2.7, 24: 2.7, 25: 2.7, 26: 2.7, 27: 2.7, 28: 2.7, 29: 2.7, 30: 2.7, 31: 2.7, 33: 2.68, 37: 2.7, 38: 2.7, 39: 2.7, 40: 2.7, 41: 2.7, 42: 2.7, 43: 2.7, 44: 2.7, 45: 2.7, 46: 2.7, 47: 2.7, 48: 2.7, 49: 2.7, 50: 2.7, 55: 2.7, 56: 2.7, 57: 2.7, 58: 2.7, 59: 2.7, 60: 2.7, 61: 2.7, 62: 2.7, 63: 2.7, 64: 2.7, 65: 2.7, 66: 2.7, 67: 2.7, 68: 2.7, 69: 2.7, 70: 2.7, 71: 2.7, 72: 2.7, 73: 2.7, 74: 2.7, 75: 2.7, 76: 2.7, 77: 2.7, 78: 2.7, 79: 2.7, 80: 2.7, 81: 2.7, 82: 2.7, 83: 2.7, 87: 2.7, 88: 2.7, 89: 2.7, 90: 2.7, 91: 2.7, 92: 2.7, 93: 2.7, 94: 2.7, 95: 2.7, 96: 2.7, 97: 2.7, 98: 2.7, 99: 2.7, 100: 2.7, 101: 2.7, 102: 2.7, 103: 2.7, 104: 2.7, 105: 2.7, 106: 2.7, 107: 2.7, 108: 2.7, 109: 2.88 };
            var __ElementPairThresholds = { 0: 0.8, 20: 1.31, 27: 1.3, 35: 1.3, 44: 1.05, 54: 1, 60: 1.84, 72: 1.88, 84: 1.75, 85: 1.56, 86: 1.76, 98: 1.6, 99: 1.68, 100: 1.63, 112: 1.55, 113: 1.59, 114: 1.36, 129: 1.45, 144: 1.6, 170: 1.4, 180: 1.55, 202: 2.4, 222: 2.24, 224: 1.91, 225: 1.98, 243: 2.02, 269: 2, 293: 1.9, 480: 2.3, 512: 2.3, 544: 2.3, 612: 2.1, 629: 1.54, 665: 1, 813: 2.6, 854: 2.27, 894: 1.93, 896: 2.1, 937: 2.05, 938: 2.06, 981: 1.62, 1258: 2.68, 1309: 2.33, 1484: 1, 1763: 2.14, 1823: 2.48, 1882: 2.1, 1944: 1.72, 2380: 2.34, 3367: 2.44, 3733: 2.11, 3819: 2.6, 3821: 2.36, 4736: 2.75, 5724: 2.73, 5959: 2.63, 6519: 2.84, 6750: 2.87, 8991: 2.81 };
            var DefaultBondingRadius = 2.001;
            var MetalsSet = (function () {
                var metals = ['LI', 'NA', 'K', 'RB', 'CS', 'FR', 'BE', 'MG', 'CA', 'SR', 'BA', 'RA', 'AL', 'GA', 'IN', 'SN', 'TL', 'PB', 'BI', 'SC', 'TI', 'V', 'CR', 'MN', 'FE', 'CO', 'NI', 'CU', 'ZN', 'Y', 'ZR', 'NB', 'MO', 'TC', 'RU', 'RH', 'PD', 'AG', 'CD', 'LA', 'HF', 'TA', 'W', 'RE', 'OS', 'IR', 'PT', 'AU', 'HG', 'AC', 'RF', 'DB', 'SG', 'BH', 'HS', 'MT', 'CE', 'PR', 'ND', 'PM', 'SM', 'EU', 'GD', 'TB', 'DY', 'HO', 'ER', 'TM', 'YB', 'LU', 'TH', 'PA', 'U', 'NP', 'PU', 'AM', 'CM', 'BK', 'CF', 'ES', 'FM', 'MD', 'NO', 'LR'];
                var set = Core.Utils.FastSet.create();
                for (var _i = 0, metals_1 = metals; _i < metals_1.length; _i++) {
                    var m = metals_1[_i];
                    set.add(__ElementIndex[m]);
                }
                return set;
            })();
            function pair(a, b) {
                if (a < b)
                    return (a + b) * (a + b + 1) / 2 + b;
                else
                    return (a + b) * (a + b + 1) / 2 + a;
            }
            function idx(e) {
                var i = __ElementIndex[e];
                if (i === void 0)
                    return -1;
                return i;
            }
            function pairThreshold(i, j) {
                if (i < 0 || j < 0)
                    return -1;
                var r = __ElementPairThresholds[pair(i, j)];
                if (r === void 0)
                    return -1;
                return r;
            }
            function threshold(i) {
                if (i < 0)
                    return DefaultBondingRadius;
                var r = __ElementBondThresholds[i];
                if (r === void 0)
                    return DefaultBondingRadius;
                return r;
            }
            var H_ID = __ElementIndex['H'];
            function isHydrogen(i) {
                return i === H_ID;
            }
            function isMetal(e) {
                var i = __ElementIndex[e];
                if (i === void 0)
                    return false;
                return MetalsSet.has(i);
            }
            function bondsFromInput(model, atomIndices) {
                var bonds = model.data.bonds.input;
                if (atomIndices.length === model.data.atoms.count)
                    return bonds;
                var mask = Core.Utils.Mask.ofIndices(model.data.atoms.count, atomIndices);
                var a = bonds.atomAIndex, b = bonds.atomBIndex, t = bonds.type;
                var count = 0;
                for (var i = 0, __i = bonds.count; i < __i; i++) {
                    if (!mask.has(a[i]) || !mask.has(b[i]))
                        continue;
                    count++;
                }
                var ret = Core.Utils.DataTable.ofDefinition(Structure.Tables.Bonds, count);
                var atomAIndex = ret.atomAIndex, atomBIndex = ret.atomBIndex, type = ret.type;
                var elementSymbol = model.data.atoms.elementSymbol;
                var offset = 0;
                for (var i = 0, __i = bonds.count; i < __i; i++) {
                    var u = a[i], v = b[i];
                    if (!mask.has(u) || !mask.has(v))
                        continue;
                    atomAIndex[offset] = u;
                    atomBIndex[offset] = v;
                    var metal = isMetal(elementSymbol[u]) || isMetal(elementSymbol[v]);
                    type[offset] = metal ? 6 /* Metallic */ : t[i];
                    offset++;
                }
                return ret;
            }
            var ChunkedAdd = Core.Utils.ChunkedArray.add;
            function addComponentBonds(_a, rI) {
                var model = _a.model, mask = _a.mask, atomA = _a.atomA, atomB = _a.atomB, type = _a.type;
                var _b = model.data.residues, atomStartIndex = _b.atomStartIndex, atomEndIndex = _b.atomEndIndex, residueName = _b.name;
                var _c = model.data.atoms, atomName = _c.name, altLoc = _c.altLoc, elementSymbol = _c.elementSymbol;
                var map = model.data.bonds.component.entries.get(residueName[rI]).map;
                var start = atomStartIndex[rI], end = atomEndIndex[rI];
                for (var i = start; i < end - 1; i++) {
                    if (!mask.has(i))
                        continue;
                    var pairs = map.get(atomName[i]);
                    if (!pairs)
                        continue;
                    var altA = altLoc[i];
                    var isMetalA = isMetal(elementSymbol[i]);
                    for (var j = i + 1; j < end; j++) {
                        if (!mask.has(j))
                            continue;
                        var altB = altLoc[j];
                        if (altA && altB && altA !== altB)
                            continue;
                        var order = pairs.get(atomName[j]);
                        if (order === void 0)
                            continue;
                        var metal = isMetalA || isMetal(elementSymbol[j]);
                        ChunkedAdd(atomA, i);
                        ChunkedAdd(atomB, j);
                        ChunkedAdd(type, metal ? 6 /* Metallic */ : order);
                    }
                }
            }
            function _computeBonds(model, atomIndices, params) {
                var MAX_RADIUS = 3;
                var _a = model.data.bonds, structConn = _a.structConn, component = _a.component;
                var _b = model.positions, x = _b.x, y = _b.y, z = _b.z;
                var _c = model.data.atoms, elementSymbol = _c.elementSymbol, residueIndex = _c.residueIndex, altLoc = _c.altLoc;
                var residueName = model.data.residues.name;
                var query3d = model.queryContext.lookup3d();
                var atomA = Core.Utils.ChunkedArray.create(function (size) { return new Int32Array(size); }, (atomIndices.length * 1.33) | 0, 1);
                var atomB = Core.Utils.ChunkedArray.create(function (size) { return new Int32Array(size); }, (atomIndices.length * 1.33) | 0, 1);
                var type = Core.Utils.ChunkedArray.create(function (size) { return new Uint8Array(size); }, (atomIndices.length * 1.33) | 0, 1);
                var mask = Core.Utils.Mask.ofIndices(model.data.atoms.count, atomIndices);
                var state = { model: model, mask: mask, atomA: atomA, atomB: atomB, type: type };
                var lastResidue = -1;
                var hasComponent = false;
                for (var _i = 0, atomIndices_1 = atomIndices; _i < atomIndices_1.length; _i++) {
                    var aI = atomIndices_1[_i];
                    var raI = residueIndex[aI];
                    if (!params.forceCompute && raI !== lastResidue) {
                        hasComponent = !!component && component.entries.has(residueName[raI]);
                        if (hasComponent) {
                            addComponentBonds(state, raI);
                        }
                    }
                    lastResidue = raI;
                    var aeI = idx(elementSymbol[aI]);
                    var _d = query3d(x[aI], y[aI], z[aI], MAX_RADIUS), elements = _d.elements, count = _d.count, squaredDistances = _d.squaredDistances;
                    var isHa = isHydrogen(aeI);
                    var thresholdA = threshold(aeI);
                    var altA = altLoc[aI];
                    var metalA = MetalsSet.has(aeI);
                    var structConnEntries = params.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI);
                    for (var ni = 0; ni < count; ni++) {
                        var bI = elements[ni];
                        if (bI <= aI || !mask.has(bI))
                            continue;
                        var altB = altLoc[bI];
                        if (altA && altB && altA !== altB)
                            continue;
                        var rbI = residueIndex[bI];
                        if (raI === rbI && hasComponent)
                            continue;
                        var beI = idx(elementSymbol[bI]);
                        var isHb = isHydrogen(beI);
                        if (isHa && isHb)
                            continue;
                        var dist = Math.sqrt(squaredDistances[ni]);
                        if (dist === 0)
                            continue;
                        if (structConnEntries) {
                            var added = false;
                            for (var _e = 0, structConnEntries_1 = structConnEntries; _e < structConnEntries_1.length; _e++) {
                                var se = structConnEntries_1[_e];
                                for (var _f = 0, _g = se.partners; _f < _g.length; _f++) {
                                    var p = _g[_f];
                                    if (p.atomIndex === bI) {
                                        ChunkedAdd(atomA, aI);
                                        ChunkedAdd(atomB, bI);
                                        ChunkedAdd(type, se.bondType);
                                        added = true;
                                        break;
                                    }
                                }
                                if (added)
                                    break;
                            }
                            if (added)
                                continue;
                        }
                        if (isHa || isHb) {
                            if (dist < params.maxHbondLength) {
                                ChunkedAdd(atomA, aI);
                                ChunkedAdd(atomB, bI);
                                ChunkedAdd(type, 1 /* Single */);
                            }
                            continue;
                        }
                        var thresholdAB = pairThreshold(aeI, beI);
                        var pairingThreshold = thresholdAB > 0
                            ? thresholdAB
                            : beI < 0 ? thresholdA : Math.max(thresholdA, threshold(beI));
                        var metalB = MetalsSet.has(beI);
                        if (dist <= pairingThreshold) {
                            ChunkedAdd(atomA, aI);
                            ChunkedAdd(atomB, bI);
                            ChunkedAdd(type, metalA || metalB ? 6 /* Metallic */ : 1 /* Single */);
                        }
                    }
                }
                var ret = Core.Utils.DataTable.builder(atomA.elementCount);
                ret.addRawColumn('atomAIndex', function (s) { return new Int32Array(s); }, Core.Utils.ChunkedArray.compact(atomA));
                ret.addRawColumn('atomBIndex', function (s) { return new Int32Array(s); }, Core.Utils.ChunkedArray.compact(atomB));
                ret.addRawColumn('type', function (s) { return new Uint8Array(s); }, Core.Utils.ChunkedArray.compact(type));
                var dataTable = ret.seal();
                return dataTable;
            }
            function computeBonds(model, atomIndices, params) {
                if (model.data.bonds.input)
                    return bondsFromInput(model, atomIndices);
                return _computeBonds(model, atomIndices, {
                    maxHbondLength: (params && params.maxHbondLength) || 1.15,
                    forceCompute: !!(params && params.forceCompute),
                });
            }
            Structure.computeBonds = computeBonds;
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            "use strict";
            var Mat4 = Core.Geometry.LinearAlgebra.Matrix4;
            var Vec4 = Core.Geometry.LinearAlgebra.Vector4;
            var Spacegroup = /** @class */ (function () {
                function Spacegroup(info) {
                    this.info = info;
                    this.temp = Mat4.zero();
                    this.tempV = new Float64Array(4);
                    if (SpacegroupTables.Spacegroup[info.spacegroupName] === void 0) {
                        throw "'" + info.spacegroupName + "' is not a spacegroup recognized by the library.";
                    }
                    this.space = this.getSpace();
                    this.operators = this.getOperators();
                }
                Object.defineProperty(Spacegroup.prototype, "operatorCount", {
                    get: function () {
                        return this.operators.length;
                    },
                    enumerable: true,
                    configurable: true
                });
                Spacegroup.prototype.getOperatorMatrix = function (index, i, j, k, target) {
                    this.tempV[0] = i;
                    this.tempV[1] = j;
                    this.tempV[2] = k;
                    Mat4.fromTranslation(this.temp, this.tempV);
                    Mat4.mul(target, Mat4.mul(target, Mat4.mul(target, this.space.fromFrac, this.temp), this.operators[index]), this.space.toFrac);
                    return target;
                };
                Spacegroup.prototype.getSpace = function () {
                    var toFrac = this.info.toFracTransform, fromFrac = Mat4.zero();
                    Mat4.invert(fromFrac, toFrac);
                    return {
                        toFrac: toFrac,
                        fromFrac: fromFrac,
                        baseX: Vec4.transform(Vec4.zero(), Vec4.fromValues(1, 0, 0, 1), toFrac),
                        baseY: Vec4.transform(Vec4.zero(), Vec4.fromValues(0, 1, 0, 1), toFrac),
                        baseZ: Vec4.transform(Vec4.zero(), Vec4.fromValues(0, 0, 1, 1), toFrac)
                    };
                };
                Spacegroup.getOperator = function (ids) {
                    var r1 = SpacegroupTables.Transform[ids[0]], r2 = SpacegroupTables.Transform[ids[1]], r3 = SpacegroupTables.Transform[ids[2]];
                    return Mat4.ofRows([r1, r2, r3, [0, 0, 0, 1]]);
                };
                Spacegroup.prototype.getOperators = function () {
                    var group = SpacegroupTables.Group[SpacegroupTables.Spacegroup[this.info.spacegroupName]];
                    return group.map(function (i) { return Spacegroup.getOperator(SpacegroupTables.Operator[i]); });
                };
                return Spacegroup;
            }());
            Structure.Spacegroup = Spacegroup;
            var SpacegroupTables;
            (function (SpacegroupTables) {
                SpacegroupTables.Transform = [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [-1.0, 0.0, 0.0, 0.0],
                    [0.0, -1.0, 0.0, 0.0],
                    [0.0, 0.0, -1.0, 0.0],
                    [0.0, 1.0, 0.0, 0.5],
                    [1.0, 0.0, 0.0, 0.5],
                    [-1.0, 0.0, 0.0, 0.5],
                    [0.0, 0.0, 1.0, 0.5],
                    [0.0, -1.0, 0.0, 0.5],
                    [0.0, 0.0, -1.0, 0.5],
                    [1.0, 0.0, 0.0, 0.25],
                    [0.0, -1.0, 0.0, 0.25],
                    [0.0, 0.0, 1.0, 0.25],
                    [-1.0, 0.0, 0.0, 0.25],
                    [0.0, 1.0, 0.0, 0.25],
                    [0.0, -1.0, 0.0, 0.75],
                    [0.0, 0.0, 1.0, 0.75],
                    [0.0, 1.0, 0.0, 0.75],
                    [1.0, 0.0, 0.0, 0.75],
                    [-1.0, 0.0, 0.0, 0.75],
                    [0.0, 0.0, -1.0, 0.25],
                    [0.0, 0.0, -1.0, 0.75],
                    [1.0, -1.0, 0.0, 0.0],
                    [-1.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.333333333333333],
                    [0.0, 0.0, 1.0, 0.666666666666667],
                    [1.0, 0.0, 0.0, 0.666666666666667],
                    [0.0, 1.0, 0.0, 0.333333333333333],
                    [0.0, -1.0, 0.0, 0.666666666666667],
                    [1.0, -1.0, 0.0, 0.333333333333333],
                    [-1.0, 1.0, 0.0, 0.666666666666667],
                    [-1.0, 0.0, 0.0, 0.333333333333333],
                    [1.0, 0.0, 0.0, 0.333333333333333],
                    [0.0, 1.0, 0.0, 0.666666666666667],
                    [0.0, -1.0, 0.0, 0.333333333333333],
                    [1.0, -1.0, 0.0, 0.666666666666667],
                    [-1.0, 1.0, 0.0, 0.333333333333333],
                    [-1.0, 0.0, 0.0, 0.666666666666667],
                    [0.0, 0.0, -1.0, 0.333333333333333],
                    [0.0, 0.0, -1.0, 0.666666666666667],
                    [0.0, 0.0, 1.0, 0.833333333333333],
                    [0.0, 0.0, 1.0, 0.166666666666667],
                    [0.0, 0.0, -1.0, 0.833333333333333],
                    [0.0, 0.0, -1.0, 0.166666666666667],
                ];
                SpacegroupTables.Operator = [
                    [0, 1, 2],
                    [3, 4, 5],
                    [3, 1, 5],
                    [3, 6, 5],
                    [7, 6, 2],
                    [8, 6, 5],
                    [0, 4, 2],
                    [0, 4, 9],
                    [7, 10, 2],
                    [7, 10, 9],
                    [0, 10, 2],
                    [8, 10, 5],
                    [3, 1, 11],
                    [3, 6, 11],
                    [0, 10, 9],
                    [8, 6, 11],
                    [3, 4, 2],
                    [0, 4, 5],
                    [3, 4, 9],
                    [7, 10, 5],
                    [8, 4, 9],
                    [8, 10, 9],
                    [8, 10, 2],
                    [0, 6, 9],
                    [3, 10, 9],
                    [0, 10, 11],
                    [7, 1, 9],
                    [8, 1, 11],
                    [7, 4, 11],
                    [7, 6, 9],
                    [7, 10, 11],
                    [3, 10, 2],
                    [8, 1, 5],
                    [0, 4, 11],
                    [3, 1, 2],
                    [3, 1, 9],
                    [7, 4, 2],
                    [8, 1, 2],
                    [8, 1, 9],
                    [3, 6, 9],
                    [7, 4, 9],
                    [8, 6, 2],
                    [8, 6, 9],
                    [3, 6, 2],
                    [12, 13, 14],
                    [15, 16, 14],
                    [12, 17, 18],
                    [15, 19, 18],
                    [20, 13, 18],
                    [21, 16, 18],
                    [20, 17, 14],
                    [21, 19, 14],
                    [0, 1, 5],
                    [8, 10, 11],
                    [7, 6, 11],
                    [7, 6, 5],
                    [8, 4, 2],
                    [7, 4, 5],
                    [7, 1, 5],
                    [7, 1, 11],
                    [0, 10, 5],
                    [0, 1, 11],
                    [0, 6, 11],
                    [0, 6, 5],
                    [3, 10, 11],
                    [8, 4, 11],
                    [15, 13, 22],
                    [12, 16, 22],
                    [15, 17, 23],
                    [12, 19, 23],
                    [21, 13, 23],
                    [20, 16, 23],
                    [21, 17, 22],
                    [20, 19, 22],
                    [4, 0, 2],
                    [1, 3, 2],
                    [4, 0, 14],
                    [1, 3, 18],
                    [4, 0, 9],
                    [1, 3, 9],
                    [4, 0, 18],
                    [1, 3, 14],
                    [10, 7, 9],
                    [6, 8, 9],
                    [4, 7, 14],
                    [6, 3, 18],
                    [10, 0, 18],
                    [1, 8, 14],
                    [1, 3, 5],
                    [4, 0, 5],
                    [6, 8, 11],
                    [10, 7, 11],
                    [1, 3, 11],
                    [4, 0, 11],
                    [10, 7, 2],
                    [6, 8, 2],
                    [3, 10, 22],
                    [7, 1, 23],
                    [8, 4, 23],
                    [0, 6, 22],
                    [1, 0, 5],
                    [4, 3, 5],
                    [1, 0, 23],
                    [4, 3, 22],
                    [10, 7, 14],
                    [6, 8, 18],
                    [8, 6, 22],
                    [7, 10, 23],
                    [4, 3, 11],
                    [1, 0, 11],
                    [1, 0, 22],
                    [4, 3, 23],
                    [10, 7, 18],
                    [6, 8, 14],
                    [8, 6, 23],
                    [7, 10, 22],
                    [6, 7, 11],
                    [10, 8, 11],
                    [8, 1, 23],
                    [0, 10, 22],
                    [3, 6, 22],
                    [7, 4, 23],
                    [4, 3, 2],
                    [1, 0, 2],
                    [10, 8, 2],
                    [6, 7, 2],
                    [4, 3, 9],
                    [1, 0, 9],
                    [10, 8, 9],
                    [6, 7, 9],
                    [4, 8, 14],
                    [6, 0, 18],
                    [10, 3, 18],
                    [1, 7, 14],
                    [4, 8, 18],
                    [6, 0, 14],
                    [10, 3, 14],
                    [1, 7, 18],
                    [6, 7, 5],
                    [10, 8, 5],
                    [6, 8, 5],
                    [10, 7, 5],
                    [8, 1, 22],
                    [0, 10, 23],
                    [3, 6, 23],
                    [7, 4, 22],
                    [4, 24, 2],
                    [25, 3, 2],
                    [4, 24, 26],
                    [25, 3, 27],
                    [4, 24, 27],
                    [25, 3, 26],
                    [28, 29, 26],
                    [30, 31, 26],
                    [32, 33, 26],
                    [34, 35, 27],
                    [36, 37, 27],
                    [38, 39, 27],
                    [2, 0, 1],
                    [1, 2, 0],
                    [1, 25, 5],
                    [24, 0, 5],
                    [39, 36, 40],
                    [35, 38, 40],
                    [37, 34, 40],
                    [33, 30, 41],
                    [29, 32, 41],
                    [31, 28, 41],
                    [5, 3, 4],
                    [4, 5, 3],
                    [25, 1, 5],
                    [0, 24, 5],
                    [24, 4, 5],
                    [3, 25, 5],
                    [4, 3, 41],
                    [25, 1, 40],
                    [24, 4, 41],
                    [3, 25, 40],
                    [4, 3, 40],
                    [25, 1, 41],
                    [24, 4, 40],
                    [3, 25, 41],
                    [35, 34, 40],
                    [37, 36, 40],
                    [39, 38, 40],
                    [29, 28, 41],
                    [31, 30, 41],
                    [33, 32, 41],
                    [3, 5, 4],
                    [5, 4, 3],
                    [25, 1, 2],
                    [0, 24, 2],
                    [24, 4, 2],
                    [3, 25, 2],
                    [25, 1, 9],
                    [0, 24, 9],
                    [24, 4, 9],
                    [3, 25, 9],
                    [30, 33, 26],
                    [32, 29, 26],
                    [28, 31, 26],
                    [36, 39, 27],
                    [38, 35, 27],
                    [34, 37, 27],
                    [0, 2, 1],
                    [2, 1, 0],
                    [30, 33, 42],
                    [32, 29, 42],
                    [28, 31, 42],
                    [36, 39, 43],
                    [38, 35, 43],
                    [34, 37, 43],
                    [7, 9, 6],
                    [9, 6, 7],
                    [25, 1, 11],
                    [0, 24, 11],
                    [24, 4, 11],
                    [3, 25, 11],
                    [35, 34, 44],
                    [37, 36, 44],
                    [39, 38, 44],
                    [29, 28, 45],
                    [31, 30, 45],
                    [33, 32, 45],
                    [8, 11, 10],
                    [11, 10, 8],
                    [1, 25, 2],
                    [24, 0, 2],
                    [1, 25, 42],
                    [24, 0, 43],
                    [1, 25, 43],
                    [24, 0, 42],
                    [1, 25, 27],
                    [24, 0, 26],
                    [1, 25, 26],
                    [24, 0, 27],
                    [1, 25, 9],
                    [24, 0, 9],
                    [4, 24, 5],
                    [25, 3, 5],
                    [4, 24, 11],
                    [25, 3, 11],
                    [1, 0, 40],
                    [4, 3, 44],
                    [0, 24, 45],
                    [1, 0, 41],
                    [4, 3, 45],
                    [0, 24, 44],
                    [0, 24, 40],
                    [0, 24, 41],
                    [2, 3, 4],
                    [5, 3, 1],
                    [5, 0, 4],
                    [4, 2, 3],
                    [1, 5, 3],
                    [4, 5, 0],
                    [2, 7, 6],
                    [2, 8, 10],
                    [5, 8, 6],
                    [5, 7, 10],
                    [1, 9, 7],
                    [4, 9, 8],
                    [1, 11, 8],
                    [4, 11, 7],
                    [9, 0, 6],
                    [9, 3, 10],
                    [11, 3, 6],
                    [11, 0, 10],
                    [6, 2, 7],
                    [10, 2, 8],
                    [6, 5, 8],
                    [10, 5, 7],
                    [9, 7, 1],
                    [9, 8, 4],
                    [11, 8, 1],
                    [11, 7, 4],
                    [6, 9, 0],
                    [10, 9, 3],
                    [6, 11, 3],
                    [10, 11, 0],
                    [9, 7, 6],
                    [9, 8, 10],
                    [11, 8, 6],
                    [11, 7, 10],
                    [6, 9, 7],
                    [10, 9, 8],
                    [6, 11, 8],
                    [10, 11, 7],
                    [2, 3, 10],
                    [5, 8, 1],
                    [11, 0, 4],
                    [10, 2, 3],
                    [1, 5, 8],
                    [4, 11, 0],
                    [5, 0, 1],
                    [2, 0, 4],
                    [2, 3, 1],
                    [1, 5, 0],
                    [4, 2, 0],
                    [1, 2, 3],
                    [11, 8, 10],
                    [11, 7, 6],
                    [9, 7, 10],
                    [9, 8, 6],
                    [10, 11, 8],
                    [6, 11, 7],
                    [10, 9, 7],
                    [6, 9, 8],
                    [5, 8, 10],
                    [5, 7, 6],
                    [2, 7, 10],
                    [2, 8, 6],
                    [4, 11, 8],
                    [1, 11, 7],
                    [4, 9, 7],
                    [1, 9, 8],
                    [11, 3, 10],
                    [11, 0, 6],
                    [9, 0, 10],
                    [9, 3, 6],
                    [10, 5, 8],
                    [6, 5, 7],
                    [10, 2, 7],
                    [6, 2, 8],
                    [11, 8, 4],
                    [11, 7, 1],
                    [9, 7, 4],
                    [9, 8, 1],
                    [10, 11, 3],
                    [6, 11, 0],
                    [10, 9, 0],
                    [6, 9, 3],
                    [22, 15, 13],
                    [22, 12, 16],
                    [14, 12, 13],
                    [14, 15, 16],
                    [13, 22, 15],
                    [16, 22, 12],
                    [13, 14, 12],
                    [16, 14, 15],
                    [22, 21, 17],
                    [22, 20, 19],
                    [14, 20, 17],
                    [14, 21, 19],
                    [13, 23, 21],
                    [16, 23, 20],
                    [13, 18, 20],
                    [16, 18, 21],
                    [23, 15, 17],
                    [23, 12, 19],
                    [18, 12, 17],
                    [18, 15, 19],
                    [17, 22, 21],
                    [19, 22, 20],
                    [17, 14, 20],
                    [19, 14, 21],
                    [23, 21, 13],
                    [23, 20, 16],
                    [18, 20, 13],
                    [18, 21, 16],
                    [17, 23, 15],
                    [19, 23, 12],
                    [17, 18, 12],
                    [19, 18, 15],
                    [5, 0, 6],
                    [2, 7, 4],
                    [9, 3, 1],
                    [6, 5, 0],
                    [4, 2, 7],
                    [1, 9, 3],
                    [0, 2, 4],
                    [3, 2, 1],
                    [0, 5, 1],
                    [2, 1, 3],
                    [2, 4, 0],
                    [5, 1, 0],
                    [7, 9, 10],
                    [8, 9, 6],
                    [7, 11, 6],
                    [9, 6, 8],
                    [9, 10, 7],
                    [11, 6, 7],
                    [1, 7, 11],
                    [4, 8, 11],
                    [1, 8, 9],
                    [4, 7, 9],
                    [0, 9, 10],
                    [3, 9, 6],
                    [3, 11, 10],
                    [0, 11, 6],
                    [2, 6, 8],
                    [2, 10, 7],
                    [5, 6, 7],
                    [5, 10, 8],
                    [6, 0, 11],
                    [10, 3, 11],
                    [6, 3, 9],
                    [10, 0, 9],
                    [7, 2, 10],
                    [8, 2, 6],
                    [8, 5, 10],
                    [7, 5, 6],
                    [9, 1, 8],
                    [9, 4, 7],
                    [11, 1, 7],
                    [11, 4, 8],
                    [7, 9, 4],
                    [8, 9, 1],
                    [8, 11, 4],
                    [7, 11, 1],
                    [9, 6, 3],
                    [9, 10, 0],
                    [11, 6, 0],
                    [11, 10, 3],
                    [19, 12, 23],
                    [13, 15, 22],
                    [16, 21, 18],
                    [17, 20, 14],
                    [20, 14, 17],
                    [21, 18, 16],
                    [15, 22, 13],
                    [12, 23, 19],
                    [18, 16, 21],
                    [14, 17, 20],
                    [23, 19, 12],
                    [22, 13, 15],
                    [19, 20, 22],
                    [13, 21, 23],
                    [16, 15, 14],
                    [17, 12, 18],
                    [20, 18, 13],
                    [21, 14, 19],
                    [15, 23, 17],
                    [12, 22, 16],
                    [18, 19, 15],
                    [14, 13, 12],
                    [23, 16, 20],
                    [22, 17, 21],
                    [16, 12, 22],
                    [17, 15, 23],
                    [19, 21, 14],
                    [13, 20, 18],
                    [12, 14, 13],
                    [15, 18, 19],
                    [21, 22, 17],
                    [20, 23, 16],
                    [14, 16, 15],
                    [18, 17, 12],
                    [22, 19, 20],
                    [23, 13, 21],
                    [16, 20, 23],
                    [17, 21, 22],
                    [19, 15, 18],
                    [13, 12, 14],
                    [12, 18, 17],
                    [15, 14, 16],
                    [21, 23, 13],
                    [20, 22, 19],
                    [14, 19, 21],
                    [18, 13, 20],
                    [22, 16, 12],
                    [23, 17, 15],
                    [19, 12, 22],
                    [17, 21, 23],
                    [16, 15, 18],
                    [13, 20, 14],
                    [20, 14, 13],
                    [15, 18, 16],
                    [21, 23, 17],
                    [12, 22, 19],
                    [18, 16, 15],
                    [14, 13, 20],
                    [22, 19, 12],
                    [23, 17, 21],
                    [3, 2, 4],
                    [3, 5, 1],
                    [0, 5, 4],
                    [2, 4, 3],
                    [5, 1, 3],
                    [5, 4, 0],
                    [1, 7, 9],
                    [4, 8, 9],
                    [1, 8, 11],
                    [4, 7, 11],
                    [0, 9, 6],
                    [3, 9, 10],
                    [3, 11, 6],
                    [0, 11, 10],
                    [2, 6, 7],
                    [2, 10, 8],
                    [5, 6, 8],
                    [5, 10, 7],
                    [6, 0, 9],
                    [10, 3, 9],
                    [6, 3, 11],
                    [10, 0, 11],
                    [7, 2, 6],
                    [8, 2, 10],
                    [8, 5, 6],
                    [7, 5, 10],
                    [9, 1, 7],
                    [9, 4, 8],
                    [11, 1, 8],
                    [11, 4, 7],
                    [7, 9, 1],
                    [8, 9, 4],
                    [8, 11, 1],
                    [7, 11, 4],
                    [9, 6, 0],
                    [9, 10, 3],
                    [11, 6, 3],
                    [11, 10, 0],
                    [8, 9, 10],
                    [8, 11, 6],
                    [7, 11, 10],
                    [9, 10, 8],
                    [11, 6, 8],
                    [11, 10, 7],
                    [6, 0, 2],
                    [10, 3, 2],
                    [6, 3, 5],
                    [10, 0, 5],
                    [7, 2, 1],
                    [8, 2, 4],
                    [8, 5, 1],
                    [7, 5, 4],
                    [9, 1, 0],
                    [9, 4, 3],
                    [11, 1, 3],
                    [11, 4, 0],
                    [1, 7, 2],
                    [4, 8, 2],
                    [1, 8, 5],
                    [4, 7, 5],
                    [0, 9, 1],
                    [3, 9, 4],
                    [3, 11, 1],
                    [0, 11, 4],
                    [2, 6, 0],
                    [2, 10, 3],
                    [5, 6, 3],
                    [5, 10, 0],
                    [0, 2, 6],
                    [3, 2, 10],
                    [3, 5, 6],
                    [0, 5, 10],
                    [2, 1, 7],
                    [2, 4, 8],
                    [5, 1, 8],
                    [5, 4, 7],
                    [16, 12, 14],
                    [13, 21, 18],
                    [19, 15, 23],
                    [17, 20, 22],
                    [12, 14, 16],
                    [21, 18, 13],
                    [15, 23, 19],
                    [20, 22, 17],
                    [14, 16, 12],
                    [18, 13, 21],
                    [23, 19, 15],
                    [22, 17, 20],
                    [19, 20, 18],
                    [17, 15, 14],
                    [16, 21, 22],
                    [13, 12, 23],
                    [20, 18, 19],
                    [15, 14, 17],
                    [21, 22, 16],
                    [12, 23, 13],
                    [18, 19, 20],
                    [14, 17, 15],
                    [22, 16, 21],
                    [23, 13, 12],
                    [6, 0, 5],
                    [10, 3, 5],
                    [6, 3, 2],
                    [10, 0, 2],
                    [7, 2, 4],
                    [8, 2, 1],
                    [8, 5, 4],
                    [7, 5, 1],
                    [9, 1, 3],
                    [9, 4, 0],
                    [11, 1, 0],
                    [11, 4, 3],
                    [1, 7, 5],
                    [4, 8, 5],
                    [1, 8, 2],
                    [4, 7, 2],
                    [0, 9, 4],
                    [3, 9, 1],
                    [3, 11, 4],
                    [0, 11, 1],
                    [2, 6, 3],
                    [2, 10, 0],
                    [5, 6, 0],
                    [5, 10, 3],
                    [0, 2, 10],
                    [3, 2, 6],
                    [3, 5, 10],
                    [0, 5, 6],
                    [2, 1, 8],
                    [2, 4, 7],
                    [5, 1, 7],
                    [5, 4, 8],
                    [21, 17, 23],
                    [20, 16, 22],
                    [12, 13, 18],
                    [15, 19, 14],
                    [23, 21, 17],
                    [22, 20, 16],
                    [18, 12, 13],
                    [14, 15, 19],
                    [17, 23, 21],
                    [16, 22, 20],
                    [13, 18, 12],
                    [19, 14, 15],
                    [21, 13, 22],
                    [20, 19, 23],
                    [12, 17, 14],
                    [15, 16, 18],
                    [23, 15, 13],
                    [22, 12, 19],
                    [18, 20, 17],
                    [14, 21, 16],
                    [17, 22, 15],
                    [16, 23, 12],
                    [13, 14, 20],
                    [19, 18, 21],
                    [15, 17, 22],
                    [12, 16, 23],
                    [20, 13, 14],
                    [21, 19, 18],
                    [22, 21, 13],
                    [23, 20, 19],
                    [14, 12, 17],
                    [18, 15, 16],
                    [13, 23, 15],
                    [19, 22, 12],
                    [17, 18, 20],
                    [16, 14, 21],
                    [15, 13, 23],
                    [12, 19, 22],
                    [20, 17, 18],
                    [21, 16, 14],
                    [22, 15, 17],
                    [23, 12, 16],
                    [14, 20, 13],
                    [18, 21, 19],
                    [13, 22, 21],
                    [19, 23, 20],
                    [17, 14, 12],
                    [16, 18, 15],
                    [6, 5, 3],
                    [4, 9, 3],
                    [9, 3, 4],
                    [5, 7, 4],
                    [4, 5, 7],
                    [5, 3, 6],
                ];
                SpacegroupTables.Group = [
                    [0],
                    [0, 1],
                    [0, 2],
                    [0, 3],
                    [0, 2, 4, 5],
                    [0, 6],
                    [0, 7],
                    [0, 6, 4, 8],
                    [0, 7, 4, 9],
                    [0, 6, 2, 1],
                    [0, 3, 1, 10],
                    [0, 6, 2, 1, 4, 8, 5, 11],
                    [0, 12, 1, 7],
                    [0, 1, 13, 14],
                    [0, 12, 1, 7, 4, 15, 11, 9],
                    [0, 16, 2, 17],
                    [0, 18, 12, 17],
                    [0, 16, 5, 19],
                    [0, 20, 13, 19],
                    [0, 18, 12, 17, 4, 21, 15, 19],
                    [0, 16, 2, 17, 4, 22, 5, 19],
                    [0, 16, 2, 17, 23, 24, 13, 25, 26, 20, 27, 28, 4, 22, 5, 19],
                    [0, 16, 17, 2, 29, 21, 30, 15],
                    [0, 20, 13, 19, 29, 31, 32, 33],
                    [0, 16, 6, 34],
                    [0, 18, 7, 34],
                    [0, 16, 7, 35],
                    [0, 16, 36, 37],
                    [0, 18, 36, 38],
                    [0, 16, 14, 39],
                    [0, 20, 40, 34],
                    [0, 16, 8, 41],
                    [0, 18, 8, 42],
                    [0, 16, 9, 42],
                    [0, 16, 6, 34, 4, 22, 8, 41],
                    [0, 18, 7, 34, 4, 21, 9, 41],
                    [0, 16, 7, 35, 4, 22, 9, 42],
                    [0, 16, 6, 34, 23, 24, 14, 39],
                    [0, 16, 10, 43, 23, 24, 7, 35],
                    [0, 16, 36, 37, 23, 24, 9, 42],
                    [0, 16, 8, 41, 23, 24, 40, 38],
                    [0, 16, 6, 34, 23, 24, 14, 39, 26, 20, 40, 38, 4, 22, 8, 41],
                    [0, 16, 44, 45, 23, 24, 46, 47, 26, 20, 48, 49, 4, 22, 50, 51],
                    [0, 16, 6, 34, 29, 21, 9, 42],
                    [0, 16, 8, 41, 29, 21, 7, 35],
                    [0, 16, 36, 37, 29, 21, 14, 39],
                    [0, 16, 2, 17, 1, 52, 6, 34],
                    [0, 16, 2, 17, 53, 54, 9, 42],
                    [0, 16, 12, 33, 1, 52, 7, 35],
                    [0, 16, 2, 17, 11, 55, 8, 41],
                    [0, 56, 2, 57, 1, 58, 6, 37],
                    [0, 56, 15, 25, 1, 58, 9, 39],
                    [0, 20, 27, 17, 1, 59, 40, 34],
                    [0, 56, 12, 28, 1, 58, 7, 38],
                    [0, 16, 5, 19, 1, 52, 8, 41],
                    [0, 22, 13, 28, 1, 55, 14, 38],
                    [0, 18, 13, 60, 1, 61, 14, 43],
                    [0, 16, 15, 30, 1, 52, 9, 42],
                    [0, 16, 5, 19, 11, 55, 6, 34],
                    [0, 21, 12, 19, 1, 54, 7, 41],
                    [0, 20, 13, 19, 1, 59, 14, 41],
                    [0, 20, 3, 30, 1, 59, 10, 42],
                    [0, 18, 12, 17, 1, 61, 7, 34, 4, 21, 15, 19, 11, 54, 9, 41],
                    [0, 24, 13, 17, 1, 62, 14, 34, 4, 20, 27, 19, 11, 59, 40, 41],
                    [0, 16, 2, 17, 1, 52, 6, 34, 4, 22, 5, 19, 11, 55, 8, 41],
                    [0, 16, 12, 33, 1, 52, 7, 35, 4, 22, 15, 30, 11, 55, 9, 42],
                    [0, 31, 3, 17, 1, 63, 10, 34, 4, 56, 32, 19, 11, 58, 36, 41],
                    [0, 22, 2, 19, 64, 59, 14, 38, 4, 16, 5, 17, 65, 62, 40, 39],
                    [0, 16, 2, 17, 1, 52, 6, 34, 23, 24, 13, 25, 64, 62, 14, 39, 26, 20, 27, 28, 65, 59, 40, 38, 4, 22, 5, 19, 11, 55, 8, 41],
                    [0, 16, 2, 17, 66, 67, 44, 45, 23, 24, 13, 25, 68, 69, 46, 47, 26, 20, 27, 28, 70, 71, 48, 49, 4, 22, 5, 19, 72, 73, 50, 51],
                    [0, 16, 2, 17, 1, 52, 6, 34, 29, 21, 15, 30, 53, 54, 9, 42],
                    [0, 16, 5, 19, 1, 52, 8, 41, 29, 21, 12, 33, 53, 54, 7, 35],
                    [0, 20, 13, 19, 1, 59, 14, 41, 29, 31, 32, 33, 53, 63, 36, 35],
                    [0, 31, 3, 17, 1, 63, 10, 34, 29, 20, 27, 30, 53, 59, 40, 42],
                    [0, 16, 74, 75],
                    [0, 18, 76, 77],
                    [0, 16, 78, 79],
                    [0, 18, 80, 81],
                    [0, 16, 74, 75, 29, 21, 82, 83],
                    [0, 21, 84, 85, 29, 16, 86, 87],
                    [0, 16, 88, 89],
                    [0, 16, 88, 89, 29, 21, 90, 91],
                    [0, 16, 74, 75, 1, 52, 88, 89],
                    [0, 16, 78, 79, 1, 52, 92, 93],
                    [0, 16, 94, 95, 11, 55, 88, 89],
                    [0, 16, 82, 83, 53, 54, 88, 89],
                    [0, 16, 74, 75, 1, 52, 88, 89, 29, 21, 82, 83, 53, 54, 90, 91],
                    [0, 21, 84, 85, 96, 97, 88, 91, 29, 16, 86, 87, 98, 99, 90, 89],
                    [0, 16, 74, 75, 2, 17, 100, 101],
                    [0, 16, 94, 95, 5, 19, 100, 101],
                    [0, 18, 76, 77, 2, 33, 102, 103],
                    [0, 18, 104, 105, 106, 107, 100, 108],
                    [0, 16, 78, 79, 2, 17, 109, 108],
                    [0, 16, 82, 83, 15, 30, 100, 101],
                    [0, 18, 80, 81, 2, 33, 110, 111],
                    [0, 18, 112, 113, 114, 115, 100, 108],
                    [0, 16, 74, 75, 2, 17, 100, 101, 29, 21, 82, 83, 15, 30, 116, 117],
                    [0, 21, 84, 85, 118, 119, 116, 101, 29, 16, 86, 87, 120, 121, 100, 117],
                    [0, 16, 74, 75, 6, 34, 122, 123],
                    [0, 16, 74, 75, 8, 41, 124, 125],
                    [0, 16, 78, 79, 7, 35, 122, 123],
                    [0, 16, 82, 83, 9, 42, 122, 123],
                    [0, 16, 74, 75, 7, 35, 126, 127],
                    [0, 16, 74, 75, 9, 42, 128, 129],
                    [0, 16, 78, 79, 6, 34, 126, 127],
                    [0, 16, 78, 79, 8, 41, 128, 129],
                    [0, 16, 74, 75, 6, 34, 122, 123, 29, 21, 82, 83, 9, 42, 128, 129],
                    [0, 16, 74, 75, 7, 35, 126, 127, 29, 21, 82, 83, 8, 41, 124, 125],
                    [0, 21, 84, 85, 6, 42, 130, 131, 29, 16, 86, 87, 9, 34, 132, 133],
                    [0, 21, 84, 85, 7, 41, 134, 135, 29, 16, 86, 87, 8, 35, 136, 137],
                    [0, 16, 89, 88, 2, 17, 122, 123],
                    [0, 16, 89, 88, 12, 33, 126, 127],
                    [0, 16, 89, 88, 5, 19, 124, 125],
                    [0, 16, 89, 88, 15, 30, 128, 129],
                    [0, 16, 88, 89, 6, 34, 100, 101],
                    [0, 16, 89, 88, 7, 35, 109, 108],
                    [0, 16, 89, 88, 8, 41, 138, 139],
                    [0, 16, 89, 88, 9, 42, 116, 117],
                    [0, 16, 89, 88, 6, 34, 100, 101, 29, 21, 91, 90, 9, 42, 116, 117],
                    [0, 16, 89, 88, 7, 35, 109, 108, 29, 21, 91, 90, 8, 41, 138, 139],
                    [0, 16, 89, 88, 2, 17, 122, 123, 29, 21, 91, 90, 15, 30, 128, 129],
                    [0, 16, 89, 88, 118, 121, 132, 131, 29, 21, 91, 90, 120, 119, 130, 133],
                    [0, 16, 74, 75, 2, 17, 100, 101, 1, 52, 88, 89, 6, 34, 122, 123],
                    [0, 16, 74, 75, 12, 33, 109, 108, 1, 52, 88, 89, 7, 35, 126, 127],
                    [0, 16, 74, 75, 2, 17, 100, 101, 11, 55, 140, 141, 8, 41, 124, 125],
                    [0, 16, 74, 75, 2, 17, 100, 101, 53, 54, 90, 91, 9, 42, 128, 129],
                    [0, 16, 74, 75, 5, 19, 138, 139, 1, 52, 88, 89, 8, 41, 124, 125],
                    [0, 16, 74, 75, 15, 30, 116, 117, 1, 52, 88, 89, 9, 42, 128, 129],
                    [0, 16, 94, 95, 5, 19, 100, 101, 11, 55, 88, 89, 6, 34, 124, 125],
                    [0, 16, 94, 95, 15, 30, 109, 108, 11, 55, 88, 89, 7, 35, 128, 129],
                    [0, 16, 78, 79, 2, 17, 109, 108, 1, 52, 92, 93, 6, 34, 126, 127],
                    [0, 16, 78, 79, 12, 33, 100, 101, 1, 52, 92, 93, 7, 35, 122, 123],
                    [0, 16, 82, 83, 12, 33, 138, 139, 53, 54, 88, 89, 8, 41, 126, 127],
                    [0, 16, 82, 83, 2, 17, 116, 117, 53, 54, 88, 89, 9, 42, 122, 123],
                    [0, 16, 78, 79, 5, 19, 116, 117, 1, 52, 92, 93, 8, 41, 128, 129],
                    [0, 16, 82, 83, 15, 30, 100, 101, 1, 52, 90, 91, 9, 42, 122, 123],
                    [0, 16, 82, 83, 15, 30, 100, 101, 53, 54, 88, 89, 6, 34, 128, 129],
                    [0, 16, 82, 83, 5, 19, 109, 108, 53, 54, 88, 89, 7, 35, 124, 125],
                    [0, 16, 74, 75, 2, 17, 100, 101, 1, 52, 88, 89, 6, 34, 122, 123, 29, 21, 82, 83, 15, 30, 116, 117, 53, 54, 90, 91, 9, 42, 128, 129],
                    [0, 16, 74, 75, 12, 33, 109, 108, 1, 52, 88, 89, 7, 35, 126, 127, 29, 21, 82, 83, 5, 19, 138, 139, 53, 54, 90, 91, 8, 41, 124, 125],
                    [0, 21, 84, 85, 118, 119, 116, 101, 96, 97, 88, 91, 9, 34, 132, 133, 29, 16, 86, 87, 120, 121, 100, 117, 98, 99, 90, 89, 6, 42, 130, 131],
                    [0, 21, 84, 85, 142, 143, 138, 108, 96, 97, 88, 91, 8, 35, 136, 137, 29, 16, 86, 87, 144, 145, 109, 139, 98, 99, 90, 89, 7, 41, 134, 135],
                    [0, 146, 147],
                    [0, 148, 149],
                    [0, 150, 151],
                    [0, 146, 147, 152, 153, 154, 155, 156, 157],
                    [0, 158, 159],
                    [0, 146, 147, 1, 160, 161],
                    [0, 146, 147, 1, 160, 161, 152, 153, 154, 162, 163, 164, 155, 156, 157, 165, 166, 167],
                    [0, 158, 159, 1, 168, 169],
                    [0, 146, 147, 101, 170, 171],
                    [0, 146, 147, 100, 172, 173],
                    [0, 148, 149, 174, 175, 171],
                    [0, 148, 149, 100, 176, 177],
                    [0, 150, 151, 178, 179, 171],
                    [0, 150, 151, 100, 180, 181],
                    [0, 146, 147, 100, 172, 173, 152, 153, 154, 182, 183, 184, 155, 156, 157, 185, 186, 187],
                    [0, 158, 159, 101, 188, 189],
                    [0, 146, 147, 122, 190, 191],
                    [0, 146, 147, 123, 192, 193],
                    [0, 146, 147, 126, 194, 195],
                    [0, 146, 147, 127, 196, 197],
                    [0, 146, 147, 122, 190, 191, 152, 153, 154, 198, 199, 200, 155, 156, 157, 201, 202, 203],
                    [0, 158, 159, 123, 204, 205],
                    [0, 146, 147, 126, 194, 195, 152, 153, 154, 206, 207, 208, 155, 156, 157, 209, 210, 211],
                    [0, 158, 159, 129, 212, 213],
                    [0, 146, 147, 101, 170, 171, 1, 160, 161, 123, 192, 193],
                    [0, 146, 147, 108, 214, 215, 1, 160, 161, 127, 196, 197],
                    [0, 146, 147, 100, 172, 173, 1, 160, 161, 122, 190, 191],
                    [0, 146, 147, 109, 216, 217, 1, 160, 161, 126, 194, 195],
                    [0, 146, 147, 100, 172, 173, 1, 160, 161, 122, 190, 191, 152, 153, 154, 182, 183, 184, 162, 163, 164, 198, 199, 200, 155, 156, 157, 185, 186, 187, 165, 166, 167, 201, 202, 203],
                    [0, 158, 159, 101, 188, 189, 1, 168, 169, 123, 204, 205],
                    [0, 146, 147, 109, 216, 217, 1, 160, 161, 126, 194, 195, 152, 153, 154, 218, 219, 220, 162, 163, 164, 206, 207, 208, 155, 156, 157, 221, 222, 223, 165, 166, 167, 209, 210, 211],
                    [0, 158, 159, 117, 224, 225, 1, 168, 169, 129, 212, 213],
                    [0, 146, 147, 16, 226, 227],
                    [0, 148, 149, 18, 228, 229],
                    [0, 150, 151, 18, 230, 231],
                    [0, 150, 151, 16, 232, 233],
                    [0, 148, 149, 16, 234, 235],
                    [0, 146, 147, 18, 236, 237],
                    [0, 146, 147, 52, 238, 239],
                    [0, 146, 147, 16, 226, 227, 1, 160, 161, 52, 238, 239],
                    [0, 146, 147, 18, 236, 237, 1, 160, 161, 61, 240, 241],
                    [0, 146, 147, 16, 226, 227, 100, 172, 173, 101, 170, 171],
                    [0, 148, 149, 18, 228, 229, 242, 172, 181, 243, 214, 244],
                    [0, 150, 151, 18, 230, 231, 245, 172, 177, 246, 214, 247],
                    [0, 150, 151, 16, 232, 233, 245, 172, 177, 174, 170, 248],
                    [0, 148, 149, 16, 234, 235, 242, 172, 181, 178, 170, 249],
                    [0, 146, 147, 18, 236, 237, 100, 172, 173, 108, 214, 215],
                    [0, 146, 147, 16, 226, 227, 122, 190, 191, 123, 192, 193],
                    [0, 146, 147, 16, 226, 227, 126, 194, 195, 127, 196, 197],
                    [0, 146, 147, 18, 236, 237, 126, 194, 195, 123, 192, 193],
                    [0, 146, 147, 18, 236, 237, 122, 190, 191, 127, 196, 197],
                    [0, 146, 147, 52, 238, 239, 122, 190, 191, 101, 170, 171],
                    [0, 146, 147, 61, 240, 241, 126, 194, 195, 101, 170, 171],
                    [0, 146, 147, 52, 238, 239, 100, 172, 173, 123, 192, 193],
                    [0, 146, 147, 61, 240, 241, 100, 172, 173, 127, 196, 197],
                    [0, 146, 147, 16, 226, 227, 100, 172, 173, 101, 170, 171, 1, 160, 161, 52, 239, 238, 122, 190, 191, 123, 192, 193],
                    [0, 146, 147, 16, 226, 227, 109, 216, 217, 108, 214, 215, 1, 160, 161, 52, 239, 238, 126, 194, 195, 127, 196, 197],
                    [0, 146, 147, 18, 236, 237, 109, 216, 217, 101, 170, 171, 1, 160, 161, 61, 241, 240, 126, 194, 195, 123, 192, 193],
                    [0, 146, 147, 18, 236, 237, 100, 172, 173, 108, 214, 215, 1, 160, 161, 61, 241, 240, 122, 190, 191, 127, 196, 197],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 29, 21, 15, 30, 280, 281, 282, 283, 284, 285, 286, 287],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 29, 31, 32, 33, 280, 288, 289, 290, 284, 291, 292, 293],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 53, 54, 9, 42, 300, 301, 302, 303, 304, 305, 306, 307],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 64, 62, 14, 39, 308, 309, 310, 311, 312, 313, 314, 315, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 65, 59, 40, 38, 316, 317, 318, 319, 320, 321, 322, 323, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 11, 55, 8, 41, 324, 325, 326, 327, 328, 329, 330, 331],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 66, 67, 44, 45, 332, 333, 334, 335, 336, 337, 338, 339, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 68, 69, 46, 47, 340, 341, 342, 343, 344, 345, 346, 347, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 70, 71, 48, 49, 348, 349, 350, 351, 352, 353, 354, 355, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 72, 73, 50, 51, 356, 357, 358, 359, 360, 361, 362, 363],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 29, 21, 15, 30, 280, 281, 282, 283, 284, 285, 286, 287, 53, 54, 9, 42, 300, 301, 302, 303, 304, 305, 306, 307],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 1, 59, 14, 41, 168, 325, 318, 311, 169, 313, 330, 323],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 1, 59, 14, 41, 168, 325, 318, 311, 169, 313, 330, 323, 29, 31, 32, 33, 280, 288, 289, 290, 284, 291, 292, 293, 53, 63, 36, 35, 300, 364, 365, 366, 304, 367, 368, 369],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 138, 139, 95, 94, 406, 407, 408, 409, 410, 411, 412, 413],
                    [0, 24, 5, 28, 158, 265, 258, 275, 159, 277, 270, 263, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 23, 16, 27, 19, 256, 273, 251, 267, 260, 269, 278, 255, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 26, 22, 13, 17, 264, 250, 274, 259, 268, 261, 254, 279, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 4, 20, 2, 25, 272, 257, 266, 252, 276, 253, 262, 271, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 29, 21, 15, 30, 280, 281, 282, 283, 284, 285, 286, 287, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 450, 415, 440, 429, 454, 431, 420, 445, 458, 447, 436, 425],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 29, 31, 32, 33, 280, 288, 289, 290, 284, 291, 292, 293, 450, 415, 440, 429, 454, 431, 420, 445, 458, 447, 436, 425],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 123, 122, 88, 89, 204, 474, 475, 476, 205, 477, 478, 479],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 123, 122, 88, 89, 204, 474, 475, 476, 205, 477, 478, 479, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 125, 124, 140, 141, 504, 505, 506, 507, 508, 509, 510, 511],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 123, 122, 88, 89, 204, 474, 475, 476, 205, 477, 478, 479, 29, 21, 15, 30, 280, 281, 282, 283, 284, 285, 286, 287, 129, 128, 90, 91, 212, 512, 513, 514, 213, 515, 516, 517],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 129, 128, 90, 91, 212, 512, 513, 514, 213, 515, 516, 517],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 129, 128, 90, 91, 212, 512, 513, 514, 213, 515, 516, 517, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 127, 126, 92, 93, 542, 543, 544, 545, 546, 547, 548, 549],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 29, 31, 32, 33, 280, 288, 289, 290, 284, 291, 292, 293, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 122, 123, 89, 88, 475, 476, 204, 474, 479, 478, 477, 205],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 53, 54, 9, 42, 300, 301, 302, 303, 304, 305, 306, 307, 128, 129, 91, 90, 513, 514, 212, 512, 517, 516, 515, 213],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 128, 129, 91, 90, 513, 514, 212, 512, 517, 516, 515, 213],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225, 53, 54, 9, 42, 300, 301, 302, 303, 304, 305, 306, 307, 122, 123, 89, 88, 475, 476, 204, 474, 479, 478, 477, 205],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 122, 123, 89, 88, 475, 476, 204, 474, 479, 478, 477, 205, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 64, 62, 14, 39, 308, 309, 310, 311, 312, 313, 314, 315, 481, 480, 483, 482, 486, 487, 484, 485, 491, 490, 489, 488, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 65, 59, 40, 38, 316, 317, 318, 319, 320, 321, 322, 323, 493, 492, 495, 494, 498, 499, 496, 497, 503, 502, 501, 500, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 138, 139, 95, 94, 406, 407, 408, 409, 410, 411, 412, 413, 11, 55, 8, 41, 324, 325, 326, 327, 328, 329, 330, 331, 124, 125, 141, 140, 506, 507, 504, 505, 511, 510, 509, 508],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 128, 129, 91, 90, 513, 514, 212, 512, 517, 516, 515, 213, 23, 24, 13, 25, 256, 257, 258, 259, 260, 261, 262, 263, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 64, 62, 14, 39, 308, 309, 310, 311, 312, 313, 314, 315, 519, 518, 521, 520, 524, 525, 522, 523, 529, 528, 527, 526, 26, 20, 27, 28, 264, 265, 266, 267, 268, 269, 270, 271, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 65, 59, 40, 38, 316, 317, 318, 319, 320, 321, 322, 323, 531, 530, 533, 532, 536, 537, 534, 535, 541, 540, 539, 538, 4, 22, 5, 19, 272, 273, 274, 275, 276, 277, 278, 279, 109, 108, 79, 78, 598, 599, 600, 601, 602, 603, 604, 605, 11, 55, 8, 41, 324, 325, 326, 327, 328, 329, 330, 331, 126, 127, 93, 92, 544, 545, 542, 543, 549, 548, 547, 546],
                    [0, 24, 5, 28, 158, 265, 258, 275, 159, 277, 270, 263, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 66, 69, 50, 49, 332, 349, 342, 359, 336, 361, 354, 347, 493, 123, 483, 140, 498, 507, 204, 485, 503, 490, 509, 205, 23, 16, 27, 19, 256, 273, 251, 267, 260, 269, 278, 255, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 68, 67, 48, 51, 340, 357, 334, 351, 344, 353, 362, 339, 124, 480, 89, 494, 506, 499, 484, 474, 511, 478, 501, 488, 26, 22, 13, 17, 264, 250, 274, 259, 268, 261, 254, 279, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 70, 73, 46, 45, 348, 333, 358, 343, 352, 345, 338, 363, 122, 492, 141, 482, 475, 487, 496, 505, 479, 510, 489, 500, 4, 20, 2, 25, 272, 257, 266, 252, 276, 253, 262, 271, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 72, 71, 44, 47, 356, 341, 350, 335, 360, 337, 346, 355, 481, 125, 495, 88, 486, 476, 504, 497, 491, 502, 477, 508],
                    [0, 24, 5, 28, 158, 265, 258, 275, 159, 277, 270, 263, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 531, 129, 521, 92, 536, 545, 212, 523, 541, 528, 547, 213, 23, 16, 27, 19, 256, 273, 251, 267, 260, 269, 278, 255, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 126, 518, 91, 532, 544, 537, 522, 512, 549, 516, 539, 526, 26, 22, 13, 17, 264, 250, 274, 259, 268, 261, 254, 279, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 128, 530, 93, 520, 513, 525, 534, 543, 517, 548, 527, 538, 4, 20, 2, 25, 272, 257, 266, 252, 276, 253, 262, 271, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 519, 127, 533, 90, 524, 514, 542, 535, 529, 540, 515, 546],
                    [0, 16, 2, 17, 158, 250, 251, 252, 159, 253, 254, 255, 100, 101, 75, 74, 370, 371, 188, 372, 373, 374, 375, 189, 1, 52, 6, 34, 168, 294, 295, 296, 169, 297, 298, 299, 122, 123, 89, 88, 475, 476, 204, 474, 479, 478, 477, 205, 29, 21, 15, 30, 280, 281, 282, 283, 284, 285, 286, 287, 116, 117, 83, 82, 376, 377, 224, 378, 379, 380, 381, 225, 53, 54, 9, 42, 300, 301, 302, 303, 304, 305, 306, 307, 128, 129, 91, 90, 513, 514, 212, 512, 517, 516, 515, 213],
                    [0, 20, 13, 19, 158, 273, 266, 259, 159, 261, 278, 271, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 1, 59, 14, 41, 168, 325, 318, 311, 169, 313, 330, 323, 551, 550, 553, 552, 556, 557, 554, 555, 561, 560, 559, 558, 29, 31, 32, 33, 280, 288, 289, 290, 284, 291, 292, 293, 450, 415, 440, 429, 454, 431, 420, 445, 458, 447, 436, 425, 53, 63, 36, 35, 300, 364, 365, 366, 304, 367, 368, 369, 563, 562, 565, 564, 568, 569, 566, 567, 573, 572, 571, 570],
                    [0, 16],
                    [0, 18],
                    [0, 16, 26, 20],
                    [0, 2, 23, 13],
                    [0, 3, 4, 32],
                    [0, 2, 29, 15],
                    [0, 3, 29, 27],
                    [0, 52],
                    [0, 63],
                    [0, 52, 26, 59],
                    [0, 63, 26, 54],
                    [0, 52, 16, 1],
                    [0, 18, 1, 61],
                    [0, 52, 16, 1, 26, 59, 20, 65],
                    [0, 31, 1, 63],
                    [0, 1, 24, 62],
                    [0, 31, 1, 63, 26, 21, 65, 54],
                    [0, 2, 57, 56],
                    [0, 60, 3, 16],
                    [0, 22, 57, 3],
                    [0, 2, 28, 20],
                    [0, 17, 13, 24],
                    [0, 20, 19, 13, 4, 24, 17, 27],
                    [0, 22, 57, 3, 4, 16, 60, 32],
                    [0, 22, 57, 3, 23, 20, 30, 12, 26, 24, 33, 15, 4, 16, 60, 32],
                    [0, 22, 57, 3, 29, 18, 27, 25],
                    [0, 22, 3, 57, 1, 55, 10, 37],
                    [0, 22, 385, 396, 3, 57, 109, 117],
                    [0, 22, 57, 3, 159, 279, 654, 655, 158, 274, 656, 657, 29, 18, 25, 27, 284, 658, 262, 269, 280, 659, 257, 267],
                ];
                SpacegroupTables.Spacegroup = {
                    "P 1": 0,
                    "P -1": 1,
                    "P 1 2 1": 2,
                    "P 1 21 1": 3,
                    "C 1 2 1": 4,
                    "P 1 m 1": 5,
                    "P 1 c 1": 6,
                    "C 1 m 1": 7,
                    "C 1 c 1": 8,
                    "P 1 2/m 1": 9,
                    "P 1 21/m 1": 10,
                    "C 1 2/m 1": 11,
                    "P 1 2/c 1": 12,
                    "P 1 21/c 1": 13,
                    "C 1 2/c 1": 14,
                    "P 2 2 2": 15,
                    "P 2 2 21": 16,
                    "P 21 21 2": 17,
                    "P 21 21 21": 18,
                    "C 2 2 21": 19,
                    "C 2 2 2": 20,
                    "F 2 2 2": 21,
                    "I 2 2 2": 22,
                    "I 21 21 21": 23,
                    "P m m 2": 24,
                    "P m c 21": 25,
                    "P c c 2": 26,
                    "P m a 2": 27,
                    "P c a 21": 28,
                    "P n c 2": 29,
                    "P m n 21": 30,
                    "P b a 2": 31,
                    "P n a 21": 32,
                    "P n n 2": 33,
                    "C m m 2": 34,
                    "C m c 21": 35,
                    "C c c 2": 36,
                    "A m m 2": 37,
                    "A b m 2": 38,
                    "A m a 2": 39,
                    "A b a 2": 40,
                    "F m m 2": 41,
                    "F d d 2": 42,
                    "I m m 2": 43,
                    "I b a 2": 44,
                    "I m a 2": 45,
                    "P 2/m 2/m 2/m": 46,
                    "P m m m": 46,
                    "P 2/n 2/n 2/n": 47,
                    "P n n n": 47,
                    "P 2/c 2/c 2/m": 48,
                    "P c c m": 48,
                    "P 2/b 2/a 2/n": 49,
                    "P b a n": 49,
                    "P 21/m 2/m 2/a": 50,
                    "P m m a": 50,
                    "P 2/n 21/n 2/a": 51,
                    "P n n a": 51,
                    "P 2/m 2/n 21/a": 52,
                    "P m n a": 52,
                    "P 21/c 2/c 2/a": 53,
                    "P c c a": 53,
                    "P 21/b 21/a 2/m": 54,
                    "P b a m": 54,
                    "P 21/c 21/c 2/n": 55,
                    "P c c n": 55,
                    "P 2/b 21/c 21/m": 56,
                    "P b c m": 56,
                    "P 21/n 21/n 2/m": 57,
                    "P n n m": 57,
                    "P 21/m 21/m 2/n": 58,
                    "P m m n": 58,
                    "P 21/b 2/c 21/n": 59,
                    "P b c n": 59,
                    "P 21/b 21/c 21/a": 60,
                    "P b c a": 60,
                    "P 21/n 21/m 21/a": 61,
                    "P n m a": 61,
                    "C 2/m 2/c 21/m": 62,
                    "C m c m": 62,
                    "C 2/m 2/c 21/a": 63,
                    "C m c a": 63,
                    "C 2/m 2/m 2/m": 64,
                    "C m m m": 64,
                    "C 2/c 2/c 2/m": 65,
                    "C c c m": 65,
                    "C 2/m 2/m 2/a": 66,
                    "C m m a": 66,
                    "C 2/c 2/c 2/a": 67,
                    "C c c a": 67,
                    "F 2/m 2/m 2/m": 68,
                    "F m m m": 68,
                    "F 2/d 2/d 2/d": 69,
                    "F d d d": 69,
                    "I 2/m 2/m 2/m": 70,
                    "I m m m": 70,
                    "I 2/b 2/a 2/m": 71,
                    "I b a m": 71,
                    "I 21/b 21/c 21/a": 72,
                    "I b c a": 72,
                    "I 21/m 21/m 21/a": 73,
                    "I m m a": 73,
                    "P 4": 74,
                    "P 41": 75,
                    "P 42": 76,
                    "P 43": 77,
                    "I 4": 78,
                    "I 41": 79,
                    "P -4": 80,
                    "I -4": 81,
                    "P 4/m": 82,
                    "P 42/m": 83,
                    "P 4/n": 84,
                    "P 42/n": 85,
                    "I 4/m": 86,
                    "I 41/a": 87,
                    "P 4 2 2": 88,
                    "P 4 21 2": 89,
                    "P 41 2 2": 90,
                    "P 41 21 2": 91,
                    "P 42 2 2": 92,
                    "P 42 21 2": 93,
                    "P 43 2 2": 94,
                    "P 43 21 2": 95,
                    "I 4 2 2": 96,
                    "I 41 2 2": 97,
                    "P 4 m m": 98,
                    "P 4 b m": 99,
                    "P 42 c m": 100,
                    "P 42 n m": 101,
                    "P 4 c c": 102,
                    "P 4 n c": 103,
                    "P 42 m c": 104,
                    "P 42 b c": 105,
                    "I 4 m m": 106,
                    "I 4 c m": 107,
                    "I 41 m d": 108,
                    "I 41 c d": 109,
                    "P -4 2 m": 110,
                    "P -4 2 c": 111,
                    "P -4 21 m": 112,
                    "P -4 21 c": 113,
                    "P -4 m 2": 114,
                    "P -4 c 2": 115,
                    "P -4 b 2": 116,
                    "P -4 n 2": 117,
                    "I -4 m 2": 118,
                    "I -4 c 2": 119,
                    "I -4 2 m": 120,
                    "I -4 2 d": 121,
                    "P 4/m 2/m 2/m": 122,
                    "P4/m m m": 122,
                    "P 4/m 2/c 2/c": 123,
                    "P4/m c c": 123,
                    "P 4/n 2/b 2/m": 124,
                    "P4/n b m": 124,
                    "P 4/n 2/n 2/c": 125,
                    "P4/n n c": 125,
                    "P 4/m 21/b 2/m": 126,
                    "P4/m b m": 126,
                    "P 4/m 21/n 2/c": 127,
                    "P4/m n c": 127,
                    "P 4/n 21/m 2/m": 128,
                    "P4/n m m": 128,
                    "P 4/n 2/c 2/c": 129,
                    "P4/n c c": 129,
                    "P 42/m 2/m 2/c": 130,
                    "P42/m m c": 130,
                    "P 42/m 2/c 2/m": 131,
                    "P42/m c m": 131,
                    "P 42/n 2/b 2/c": 132,
                    "P42/n b c": 132,
                    "P 42/n 2/n 2/m": 133,
                    "P42/n n m": 133,
                    "P 42/m 21/b 2/c": 134,
                    "P42/m b c": 134,
                    "P 42/m 21/n 2/m": 135,
                    "P42/m n m": 135,
                    "P 42/n 21/m 2/c": 136,
                    "P42/n m c": 136,
                    "P 42/n 21/c 2/m": 137,
                    "P42/n c m": 137,
                    "I 4/m 2/m 2/m": 138,
                    "I4/m m m": 138,
                    "I 4/m 2/c 2/m": 139,
                    "I4/m c m": 139,
                    "I 41/a 2/m 2/d": 140,
                    "I41/a m d": 140,
                    "I 41/a 2/c 2/d": 141,
                    "I41/a c d": 141,
                    "P 3": 142,
                    "P 31": 143,
                    "P 32": 144,
                    "H 3": 145,
                    "R 3": 146,
                    "P -3": 147,
                    "H -3": 148,
                    "R -3": 149,
                    "P 3 1 2": 150,
                    "P 3 2 1": 151,
                    "P 31 1 2": 152,
                    "P 31 2 1": 153,
                    "P 32 1 2": 154,
                    "P 32 2 1": 155,
                    "H 3 2": 156,
                    "R 3 2": 157,
                    "P 3 m 1": 158,
                    "P 3 1 m": 159,
                    "P 3 c 1": 160,
                    "P 3 1 c": 161,
                    "H 3 m": 162,
                    "R 3 m": 163,
                    "H 3 c": 164,
                    "R 3 c": 165,
                    "P -3 1 2/m": 166,
                    "P -3 1 m": 166,
                    "P -3 1 2/c": 167,
                    "P -3 1 c": 167,
                    "P -3 2/m 1": 168,
                    "P -3 m 1": 168,
                    "P -3 2/c 1": 169,
                    "P -3 c 1": 169,
                    "H -3 2/m": 170,
                    "H -3 m": 170,
                    "R -3 2/m": 171,
                    "R -3 m": 171,
                    "H -3 2/c": 172,
                    "H -3 c": 172,
                    "R -3 2/c": 173,
                    "R -3 c": 173,
                    "P 6": 174,
                    "P 61": 175,
                    "P 65": 176,
                    "P 62": 177,
                    "P 64": 178,
                    "P 63": 179,
                    "P -6": 180,
                    "P 6/m": 181,
                    "P 63/m": 182,
                    "P 6 2 2": 183,
                    "P 61 2 2": 184,
                    "P 65 2 2": 185,
                    "P 62 2 2": 186,
                    "P 64 2 2": 187,
                    "P 63 2 2": 188,
                    "P 6 m m": 189,
                    "P 6 c c": 190,
                    "P 63 c m": 191,
                    "P 63 m c": 192,
                    "P -6 m 2": 193,
                    "P -6 c 2": 194,
                    "P -6 2 m": 195,
                    "P -6 2 c": 196,
                    "P 6/m 2/m 2/m": 197,
                    "P 6/m m m": 197,
                    "P 6/m 2/c 2/c": 198,
                    "P 6/m c c": 198,
                    "P 63/m 2/c 2/m": 199,
                    "P 63/m c m": 199,
                    "P 63/m 2/m 2/c": 200,
                    "P 63/m m c": 200,
                    "P 2 3": 201,
                    "F 2 3": 202,
                    "I 2 3": 203,
                    "P 21 3": 204,
                    "I 21 3": 205,
                    "P 2/m -3": 206,
                    "P m -3": 206,
                    "P 2/n -3": 207,
                    "P n -3": 207,
                    "F 2/m -3": 208,
                    "F m -3": 208,
                    "F 2/d -3": 209,
                    "F d -3": 209,
                    "I 2/m -3": 210,
                    "I m -3": 210,
                    "P 21/a -3": 211,
                    "P a -3": 211,
                    "I 21/a -3": 212,
                    "I a -3": 212,
                    "P 4 3 2": 213,
                    "P 42 3 2": 214,
                    "F 4 3 2": 215,
                    "F 41 3 2": 216,
                    "I 4 3 2": 217,
                    "P 43 3 2": 218,
                    "P 41 3 2": 219,
                    "I 41 3 2": 220,
                    "P -4 3 m": 221,
                    "F -4 3 m": 222,
                    "I -4 3 m": 223,
                    "P -4 3 n": 224,
                    "F -4 3 c": 225,
                    "I -4 3 d": 226,
                    "P 4/m -3 2/m": 227,
                    "P m -3 m": 227,
                    "P 4/n -3 2/n": 228,
                    "P n -3 n": 228,
                    "P 42/m -3 2/n": 229,
                    "P m -3 n": 229,
                    "P 42/n -3 2/m": 230,
                    "P n -3 m": 230,
                    "F 4/m -3 2/m": 231,
                    "F m -3 m": 231,
                    "F 4/m -3 2/c": 232,
                    "F m -3 c": 232,
                    "F 41/d -3 2/m": 233,
                    "F d -3 m": 233,
                    "F 41/d -3 2/c": 234,
                    "F d -3 c": 234,
                    "I 4/m -3 2/m": 235,
                    "I m -3 m": 235,
                    "I 41/a -3 2/d": 236,
                    "I a -3 d": 236,
                    "P 1 1 2": 237,
                    "P 1 1 21": 238,
                    "B 1 1 2": 239,
                    "B 2": 239,
                    "A 1 2 1": 240,
                    "C 1 21 1": 241,
                    "I 1 2 1": 242,
                    "I 2": 242,
                    "I 1 21 1": 243,
                    "P 1 1 m": 244,
                    "P 1 1 b": 245,
                    "B 1 1 m": 246,
                    "B 1 1 b": 247,
                    "P 1 1 2/m": 248,
                    "P 1 1 21/m": 249,
                    "B 1 1 2/m": 250,
                    "P 1 1 2/b": 251,
                    "P 1 1 21/b": 252,
                    "B 1 1 2/b": 253,
                    "P 21 2 2": 254,
                    "P 2 21 2": 255,
                    "P 21 21 2 (a)": 256,
                    "P 21 2 21": 257,
                    "P 2 21 21": 258,
                    "C 2 2 21a)": 259,
                    "C 2 2 2a": 260,
                    "F 2 2 2a": 261,
                    "I 2 2 2a": 262,
                    "P 21/m 21/m 2/n a": 263,
                    "P 42 21 2a": 264,
                    "I 2 3a": 265,
                };
            })(SpacegroupTables = Structure.SpacegroupTables || (Structure.SpacegroupTables = {}));
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            'use strict';
            var DataTable = Core.Utils.DataTable;
            var SymmetryHelpers;
            (function (SymmetryHelpers) {
                var Mat4 = Core.Geometry.LinearAlgebra.Matrix4;
                var Vec3 = Core.Geometry.LinearAlgebra.Vector3;
                function getBoudingSphere(arrays, indices) {
                    var x = arrays.x, y = arrays.y, z = arrays.z;
                    var center = Vec3.zero();
                    for (var _i = 0, indices_3 = indices; _i < indices_3.length; _i++) {
                        var aI = indices_3[_i];
                        center[0] += x[aI];
                        center[1] += y[aI];
                        center[2] += z[aI];
                    }
                    var count = indices.length > 0 ? indices.length : 1;
                    center[0] /= count;
                    center[1] /= count;
                    center[2] /= count;
                    var r = 0;
                    for (var _a = 0, indices_4 = indices; _a < indices_4.length; _a++) {
                        var aI = indices_4[_a];
                        r = Math.max(indexedVectorDistSq(aI, center, arrays), r);
                    }
                    return { center: center, radius: Math.sqrt(r) };
                }
                function getSphereDist(c, r, q) {
                    return Vec3.distance(c, q.center) - (r + q.radius);
                }
                function isWithinRadius(bounds, i, data, t, r, v) {
                    v[0] = data.x[i];
                    v[1] = data.y[i];
                    v[2] = data.z[i];
                    Vec3.transformMat4(v, v, t);
                    return getSphereDist(v, data.r[i], bounds) <= r;
                }
                function indexedDistSq(aI, cI, arrays) {
                    var dx = arrays.x[aI] - arrays.cX[cI], dy = arrays.y[aI] - arrays.cY[cI], dz = arrays.z[aI] - arrays.cZ[cI];
                    return dx * dx + dy * dy + dz * dz;
                }
                function indexedVectorDistSq(aI, v, arrays) {
                    var dx = arrays.x[aI] - v[0], dy = arrays.y[aI] - v[1], dz = arrays.z[aI] - v[2];
                    return dx * dx + dy * dy + dz * dz;
                }
                function createSymmetryContext(model, boundingInfo, spacegroup, radius) {
                    return {
                        model: model,
                        boundingInfo: boundingInfo,
                        spacegroup: spacegroup,
                        radius: radius,
                        transform: Mat4.zero(),
                        transformed: Vec3.zero(),
                        i: 0, j: 0, k: 0, op: 0
                    };
                }
                function symmetryContextMap(ctx, p) {
                    return Vec3.transformMat4(ctx.transformed, p, ctx.transform);
                }
                function symmetryContextGetTransform(ctx) {
                    return createSymmetryTransform(ctx.i, ctx.j, ctx.k, ctx.op, Mat4.clone(ctx.transform));
                }
                function createSymmetryTransform(i, j, k, opIndex, transform) {
                    return {
                        isIdentity: !i && !j && !k && !opIndex,
                        id: opIndex + 1 + "_" + (5 + i) + (5 + j) + (5 + k),
                        transform: transform
                    };
                }
                function createAssemblyTransform(i, transform) {
                    var isIdentity = true;
                    for (var i_1 = 0; i_1 < 4; i_1++) {
                        for (var j = 0; j < 4; j++) {
                            var v = transform[4 * j + i_1];
                            if (i_1 === j) {
                                if (Math.abs(v - 1) > 0.0000001) {
                                    isIdentity = false;
                                    break;
                                }
                            }
                            else if (Math.abs(v) > 0.0000001) {
                                isIdentity = false;
                                break;
                            }
                        }
                        if (!isIdentity)
                            break;
                    }
                    return {
                        isIdentity: isIdentity,
                        id: i.toString(),
                        transform: transform
                    };
                }
                function getBoundingInfo(model, pivotIndices) {
                    var atoms = model.data.atoms, residues = model.data.residues, chains = model.data.chains, entities = model.data.entities, _a = model.positions, x = _a.x, y = _a.y, z = _a.z;
                    var entityTable = DataTable.builder(entities.count), eX = entityTable.addColumn('x', function (s) { return new Float64Array(s); }), eY = entityTable.addColumn('y', function (s) { return new Float64Array(s); }), eZ = entityTable.addColumn('z', function (s) { return new Float64Array(s); }), eR = entityTable.addColumn('r', function (s) { return new Float64Array(s); }), chainTable = DataTable.builder(chains.count), cX = chainTable.addColumn('x', function (s) { return new Float64Array(s); }), cY = chainTable.addColumn('y', function (s) { return new Float64Array(s); }), cZ = chainTable.addColumn('z', function (s) { return new Float64Array(s); }), cR = chainTable.addColumn('r', function (s) { return new Float64Array(s); }), residueTable = DataTable.builder(residues.count), rX = residueTable.addColumn('x', function (s) { return new Float64Array(s); }), rY = residueTable.addColumn('y', function (s) { return new Float64Array(s); }), rZ = residueTable.addColumn('z', function (s) { return new Float64Array(s); }), rR = residueTable.addColumn('r', function (s) { return new Float64Array(s); });
                    var allCenter = Vec3.zero(), allRadius = 0, pivotCenter = Vec3.zero(), pivotRadius = 0, n = 0, eCenter = Vec3.zero(), eRadius = 0, cCenter = Vec3.zero(), cRadius = 0, rCenter = Vec3.zero(), rRadius = 0;
                    for (var eI = 0, _eC = entities.count; eI < _eC; eI++) {
                        Vec3.set(eCenter, 0, 0, 0);
                        for (var cI = entities.chainStartIndex[eI], _cC = entities.chainEndIndex[eI]; cI < _cC; cI++) {
                            Vec3.set(cCenter, 0, 0, 0);
                            for (var rI = chains.residueStartIndex[cI], _rC = chains.residueEndIndex[cI]; rI < _rC; rI++) {
                                Vec3.set(rCenter, 0, 0, 0);
                                for (var aI = residues.atomStartIndex[rI], _aC = residues.atomEndIndex[rI]; aI < _aC; aI++) {
                                    rCenter[0] += x[aI];
                                    rCenter[1] += y[aI];
                                    rCenter[2] += z[aI];
                                }
                                Vec3.add(allCenter, allCenter, rCenter);
                                n = residues.atomEndIndex[rI] - residues.atomStartIndex[rI];
                                Vec3.add(cCenter, cCenter, rCenter);
                                rX[rI] = rCenter[0] / n;
                                rY[rI] = rCenter[1] / n;
                                rZ[rI] = rCenter[2] / n;
                            }
                            Vec3.add(eCenter, eCenter, cCenter);
                            n = chains.atomEndIndex[cI] - chains.atomStartIndex[cI];
                            cX[cI] = cCenter[0] / n;
                            cY[cI] = cCenter[1] / n;
                            cZ[cI] = cCenter[2] / n;
                        }
                        n = entities.atomEndIndex[eI] - entities.atomStartIndex[eI];
                        eX[eI] = eCenter[0] / n;
                        eY[eI] = eCenter[1] / n;
                        eZ[eI] = eCenter[2] / n;
                    }
                    allCenter[0] /= atoms.count;
                    allCenter[1] /= atoms.count;
                    allCenter[2] /= atoms.count;
                    for (var _i = 0, pivotIndices_1 = pivotIndices; _i < pivotIndices_1.length; _i++) {
                        var aI = pivotIndices_1[_i];
                        pivotCenter[0] += x[aI];
                        pivotCenter[1] += y[aI];
                        pivotCenter[2] += z[aI];
                    }
                    var pivotCount = pivotIndices.length > 0 ? pivotIndices.length : 1;
                    pivotCenter[0] /= pivotCount;
                    pivotCenter[1] /= pivotCount;
                    pivotCenter[2] /= pivotCount;
                    var eDA = { x: x, y: y, z: z, cX: eX, cY: eY, cZ: eZ }, cDA = { x: x, y: y, z: z, cX: cX, cY: cY, cZ: cZ }, rDA = { x: x, y: y, z: z, cX: rX, cY: rY, cZ: rZ };
                    for (var eI = 0, _eC = entities.count; eI < _eC; eI++) {
                        eRadius = 0;
                        for (var cI = entities.chainStartIndex[eI], _cC = entities.chainEndIndex[eI]; cI < _cC; cI++) {
                            cRadius = 0;
                            for (var rI = chains.residueStartIndex[cI], _rC = chains.residueEndIndex[cI]; rI < _rC; rI++) {
                                rRadius = 0;
                                for (var aI = residues.atomStartIndex[rI], _aC = residues.atomEndIndex[rI]; aI < _aC; aI++) {
                                    rRadius = Math.max(rRadius, indexedDistSq(aI, rI, rDA));
                                    cRadius = Math.max(cRadius, indexedDistSq(aI, cI, cDA));
                                    eRadius = Math.max(eRadius, indexedDistSq(aI, eI, eDA));
                                    allRadius = Math.max(allRadius, indexedVectorDistSq(aI, allCenter, rDA));
                                }
                                rRadius = Math.sqrt(rRadius);
                                rR[rI] = rRadius;
                            }
                            cRadius = Math.sqrt(cRadius);
                            cR[cI] = cRadius;
                        }
                        eRadius = Math.sqrt(eRadius);
                        eR[eI] = eRadius;
                    }
                    allRadius = Math.sqrt(allRadius);
                    for (var _b = 0, pivotIndices_2 = pivotIndices; _b < pivotIndices_2.length; _b++) {
                        var aI = pivotIndices_2[_b];
                        pivotRadius = Math.max(pivotRadius, indexedVectorDistSq(aI, pivotCenter, rDA));
                    }
                    pivotRadius = Math.sqrt(pivotRadius);
                    return {
                        entities: entityTable.seal(),
                        chains: chainTable.seal(),
                        residues: residueTable.seal(),
                        allAtoms: { center: allCenter, radius: allRadius },
                        target: { center: pivotCenter, radius: pivotRadius }
                    };
                }
                function findSuitableTransforms(ctx) {
                    var bounds = ctx.boundingInfo, sg = ctx.spacegroup;
                    var ret = [];
                    ctx.transform = Mat4.identity();
                    ret[0] = symmetryContextGetTransform(ctx);
                    for (var i = -3; i <= 3; i++) {
                        for (var j = -3; j <= 3; j++) {
                            for (var k = -3; k <= 3; k++) {
                                for (var l = (i === 0 && j === 0 && k === 0 ? 1 : 0), lm = sg.operatorCount; l < lm; l++) {
                                    sg.getOperatorMatrix(l, i, j, k, ctx.transform);
                                    ctx.i = i;
                                    ctx.k = k;
                                    ctx.j = j;
                                    ctx.op = l;
                                    var t = symmetryContextMap(ctx, bounds.allAtoms.center), d = getSphereDist(t, bounds.allAtoms.radius, bounds.target);
                                    if (d < ctx.radius) {
                                        ret[ret.length] = symmetryContextGetTransform(ctx);
                                    }
                                }
                            }
                        }
                    }
                    return ret;
                }
                function getSymmetryResidues(ctx, transforms) {
                    var bounds = ctx.boundingInfo, radius = ctx.radius, targetBounds = bounds.target;
                    var model = ctx.model, residues = model.data.residues, chains = model.data.chains, entities = model.data.entities;
                    var residueIndices = Core.Utils.ChunkedArray.create(function (s) { return new Int32Array(s); }, residues.count, 1), operatorIndices = Core.Utils.ChunkedArray.create(function (s) { return new Int32Array(s); }, residues.count, 1);
                    var v = Vec3.zero(), opIndex = 0;
                    var atomCount = 0, chainCount = 0, entityCount = 0;
                    for (var eI = 0, _eC = entities.count; eI < _eC; eI++) {
                        opIndex = 0;
                        var chainAdded = false;
                        for (var _i = 0, transforms_1 = transforms; _i < transforms_1.length; _i++) {
                            var t = transforms_1[_i];
                            for (var cI = entities.chainStartIndex[eI], _cC = entities.chainEndIndex[eI]; cI < _cC; cI++) {
                                if (!isWithinRadius(targetBounds, cI, bounds.chains, t.transform, radius, v))
                                    continue;
                                var residueAdded = false;
                                for (var rI = chains.residueStartIndex[cI], _rC = chains.residueEndIndex[cI]; rI < _rC; rI++) {
                                    if (!isWithinRadius(targetBounds, rI, bounds.residues, t.transform, radius, v))
                                        continue;
                                    Core.Utils.ChunkedArray.add(residueIndices, rI);
                                    Core.Utils.ChunkedArray.add(operatorIndices, opIndex);
                                    atomCount += residues.atomEndIndex[rI] - residues.atomStartIndex[rI];
                                    residueAdded = true;
                                }
                                if (residueAdded) {
                                    chainCount += 1;
                                    chainAdded = true;
                                }
                            }
                            opIndex++;
                        }
                        if (chainAdded) {
                            entityCount++;
                        }
                    }
                    return {
                        residues: Core.Utils.ChunkedArray.compact(residueIndices),
                        operators: Core.Utils.ChunkedArray.compact(operatorIndices),
                        atomCount: atomCount,
                        chainCount: chainCount,
                        entityCount: entityCount
                    };
                }
                function cloneRow(src, sI, target, tI, c) {
                    for (var i = 0; i < c; i++) {
                        target[i][tI] = src[i][sI];
                    }
                }
                function assemble(model, assemblyParts, transforms) {
                    var residues = model.data.residues, residueChainIndex = residues.chainIndex, residueEntityIndex = residues.entityIndex, residueAtomStartIndex = residues.atomStartIndex, residueAtomEndIndex = residues.atomEndIndex, atoms = model.data.atoms, _a = model.positions, x = _a.x, y = _a.y, z = _a.z;
                    var atomTable = DataTable.builder(assemblyParts.atomCount), atomId, atomResidue, atomChain, atomEntity, cols = [];
                    var positionTable = DataTable.ofDefinition(Structure.Tables.Positions, assemblyParts.atomCount), atomX = positionTable.x, atomY = positionTable.y, atomZ = positionTable.z;
                    var entityTableBuilder = model.data.entities.getBuilder(assemblyParts.entityCount), entityTable = entityTableBuilder, srcEntityData = model.data.entities.getRawData(), entityData = entityTable.getRawData(), entityChainStart = entityTable.chainStartIndex, entityChainEnd = entityTable.chainEndIndex, entityResidueStart = entityTable.residueStartIndex, entityResidueEnd = entityTable.residueEndIndex, entityAtomStart = entityTable.atomStartIndex, entityAtomEnd = entityTable.atomEndIndex, entityOffset = 0;
                    var chainTableBuilder = model.data.chains.getBuilder(assemblyParts.chainCount), chainTable = chainTableBuilder, srcChainData = model.data.chains.getRawData(), chainData = chainTable.getRawData(), chainResidueStart = chainTable.residueStartIndex, chainResidueEnd = chainTable.residueEndIndex, chainAtomStart = chainTable.atomStartIndex, chainAtomEnd = chainTable.atomEndIndex, chainId = chainTable.asymId, chainAuthId = chainTable.authAsymId, chainEntity = chainTable.entityIndex, chainSourceChainIndex = chainTableBuilder.addColumn('sourceChainIndex', function (s) { return new Int32Array(s); }), chainOperatorIndex = chainTableBuilder.addColumn('operatorIndex', function (s) { return new Int32Array(s); }), chainOffset = 0;
                    var residueTableBuilder = model.data.residues.getBuilder(assemblyParts.residues.length), residueTable = residueTableBuilder, srcResidueData = model.data.residues.getRawData(), residueData = residueTable.getRawData(), residueAtomStart = residueTable.atomStartIndex, residueAtomEnd = residueTable.atomEndIndex, residueAsymId = residueTable.asymId, residueAuthAsymId = residueTable.authAsymId, residueChain = residueTable.chainIndex, residueEntity = residueTable.entityIndex;
                    for (var _i = 0, _b = model.data.atoms.columns; _i < _b.length; _i++) {
                        var col = _b[_i];
                        var c = atomTable.addColumn(col.name, col.creator);
                        if (col.name === 'residueIndex')
                            atomResidue = c;
                        else if (col.name === 'chainIndex')
                            atomChain = c;
                        else if (col.name === 'entityIndex')
                            atomEntity = c;
                        else if (col.name === 'id')
                            atomId = c;
                        else {
                            cols[cols.length] = {
                                src: atoms[col.name],
                                target: c
                            };
                        }
                    }
                    var assemblyResidueParts = assemblyParts.residues, assemblyOpParts = assemblyParts.operators, temp = Core.Geometry.LinearAlgebra.Vector3.zero(), atomOffset = 0;
                    var rI = assemblyResidueParts[0], currentChain = residueChainIndex[rI], currentEntity = residueEntityIndex[rI], currentOp = assemblyOpParts[0], currentAsymId, currentAuthAsymId;
                    // setup entity table
                    cloneRow(srcEntityData, residueEntityIndex[rI], entityData, 0, srcEntityData.length);
                    entityChainStart[0] = 0;
                    entityResidueStart[0] = 0;
                    entityAtomStart[0] = 0;
                    //setup chain table
                    cloneRow(srcChainData, residueChainIndex[rI], chainData, 0, srcChainData.length);
                    chainEntity[0] = 0;
                    chainResidueStart[0] = 0;
                    chainAtomStart[0] = 0;
                    currentAsymId = model.data.chains.asymId[residueChainIndex[rI]];
                    currentAuthAsymId = model.data.chains.authAsymId[residueChainIndex[rI]];
                    var transform = transforms[assemblyOpParts[0]];
                    if (transform && !transform.isIdentity) {
                        chainId[chainOffset] = model.data.chains.asymId[residueChainIndex[rI]] + '-' + transform.id;
                        chainAuthId[chainOffset] = model.data.chains.authAsymId[residueChainIndex[rI]] + '-' + transform.id;
                        chainSourceChainIndex[chainOffset] = residueChainIndex[rI];
                        chainOperatorIndex[chainOffset] = currentOp;
                        currentAsymId = chainId[chainOffset];
                        currentAuthAsymId = chainAuthId[chainOffset];
                    }
                    for (var residueOffset = 0, _mi = assemblyResidueParts.length; residueOffset < _mi; residueOffset++) {
                        rI = assemblyResidueParts[residueOffset];
                        var opI = assemblyOpParts[residueOffset];
                        transform = transforms[opI];
                        cloneRow(srcResidueData, rI, residueData, residueOffset, residueData.length);
                        var cE = residueEntityIndex[rI], cC = residueChainIndex[rI];
                        var chainChanged = false;
                        if (cE !== currentEntity) {
                            // update chain
                            chainResidueEnd[chainOffset] = residueOffset;
                            chainAtomEnd[chainOffset] = atomOffset;
                            chainOffset += 1;
                            // update entity
                            entityChainEnd[entityOffset] = chainOffset;
                            entityResidueEnd[entityOffset] = residueOffset;
                            entityAtomEnd[entityOffset] = atomOffset;
                            // new entity
                            entityOffset += 1;
                            cloneRow(srcEntityData, cE, entityData, entityOffset, srcEntityData.length);
                            entityChainStart[entityOffset] = chainOffset;
                            entityResidueStart[entityOffset] = residueOffset;
                            entityAtomStart[entityOffset] = atomOffset;
                            chainChanged = true;
                        }
                        else if (cC !== currentChain) {
                            // update chain
                            chainResidueEnd[chainOffset] = residueOffset;
                            chainAtomEnd[chainOffset] = atomOffset;
                            chainOffset += 1;
                            chainChanged = true;
                        }
                        else if (opI !== currentOp) {
                            // update chain
                            chainResidueEnd[chainOffset] = residueOffset;
                            chainAtomEnd[chainOffset] = atomOffset;
                            chainOffset += 1;
                            chainChanged = true;
                        }
                        if (chainChanged) {
                            // new chain
                            cloneRow(srcChainData, cC, chainData, chainOffset, srcChainData.length);
                            chainEntity[chainOffset] = entityOffset;
                            chainResidueStart[chainOffset] = residueOffset;
                            chainAtomStart[chainOffset] = atomOffset;
                            // update the chain identifier if needed
                            if (!transform.isIdentity) {
                                chainId[chainOffset] = model.data.chains.asymId[cC] + '-' + transform.id;
                                chainAuthId[chainOffset] = model.data.chains.authAsymId[cC] + '-' + transform.id;
                            }
                            chainSourceChainIndex[chainOffset] = cC;
                            chainOperatorIndex[chainOffset] = opI;
                            currentAsymId = chainId[chainOffset];
                            currentAuthAsymId = chainAuthId[chainOffset];
                        }
                        currentChain = cC;
                        currentEntity = cE;
                        currentOp = opI;
                        residueChain[residueOffset] = chainOffset;
                        residueEntity[residueOffset] = entityOffset;
                        residueAtomStart[residueOffset] = atomOffset;
                        residueAsymId[residueOffset] = currentAsymId;
                        residueAuthAsymId[residueOffset] = currentAuthAsymId;
                        for (var aI = residueAtomStartIndex[rI], _mAI = residueAtomEndIndex[rI]; aI < _mAI; aI++) {
                            Vec3.set(temp, x[aI], y[aI], z[aI]);
                            Vec3.transformMat4(temp, temp, transform.transform);
                            atomX[atomOffset] = temp[0];
                            atomY[atomOffset] = temp[1];
                            atomZ[atomOffset] = temp[2];
                            atomId[atomOffset] = atomOffset + 1;
                            atomResidue[atomOffset] = residueOffset;
                            atomChain[atomOffset] = chainOffset;
                            atomEntity[atomOffset] = entityOffset;
                            for (var _c = 0, cols_1 = cols; _c < cols_1.length; _c++) {
                                var c = cols_1[_c];
                                c.target[atomOffset] = c.src[aI];
                            }
                            atomOffset++;
                        }
                        residueAtomEnd[residueOffset] = atomOffset;
                    }
                    // finalize entity
                    entityChainEnd[entityOffset] = chainOffset + 1;
                    entityResidueEnd[entityOffset] = assemblyResidueParts.length;
                    entityAtomEnd[entityOffset] = atomOffset;
                    // finalize chain
                    chainResidueEnd[chainOffset] = assemblyResidueParts.length;
                    chainAtomEnd[chainOffset] = atomOffset;
                    var finalAtoms = atomTable.seal(), finalResidues = residueTableBuilder.seal(), finalChains = chainTableBuilder.seal(), finalEntities = entityTableBuilder.seal();
                    var secondaryStructure = buildSS(model, assemblyParts, finalResidues);
                    var structConn = model.data.bonds.structConn
                        ? buildStructConn(model.data.bonds.structConn, transforms, assemblyParts.residues, assemblyParts.operators, model.data.residues, finalResidues)
                        : void 0;
                    return Structure.Molecule.Model.create({
                        id: model.id,
                        modelId: model.modelId,
                        data: {
                            atoms: finalAtoms,
                            residues: finalResidues,
                            chains: finalChains,
                            entities: finalEntities,
                            bonds: {
                                structConn: structConn,
                                component: model.data.bonds.component
                            },
                            secondaryStructure: secondaryStructure
                        },
                        positions: positionTable,
                        parent: model,
                        source: Structure.Molecule.Model.Source.Computed,
                        operators: transforms.map(function (t) { return new Structure.Operator(t.transform, t.id, t.isIdentity); })
                    });
                }
                function buildStructConn(structConn, ops, residueParts, residueOpParts, oldResidues, newResidues) {
                    var entries = structConn.entries;
                    var opsMap = Core.Utils.FastMap.create();
                    for (var i = 0, __i = ops.length; i < __i; i++) {
                        opsMap.set(ops[i].id, i);
                    }
                    var transformMap = Core.Utils.FastMap.create();
                    for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
                        var e = entries_1[_i];
                        for (var _a = 0, _b = e.partners; _a < _b.length; _a++) {
                            var p = _b[_a];
                            if (!transformMap.has(p.residueIndex)) {
                                transformMap.set(p.residueIndex, Core.Utils.FastMap.create());
                            }
                        }
                    }
                    for (var i = 0, __i = residueParts.length; i < __i; i++) {
                        var r = residueParts[i];
                        if (!transformMap.has(r))
                            continue;
                        transformMap.get(r).set(residueOpParts[i], i);
                    }
                    var oldStart = oldResidues.atomStartIndex;
                    var newStart = newResidues.atomStartIndex;
                    var ret = [];
                    for (var _c = 0, entries_2 = entries; _c < entries_2.length; _c++) {
                        var e = entries_2[_c];
                        var allId = true;
                        for (var _d = 0, _e = e.partners; _d < _e.length; _d++) {
                            var p = _e[_d];
                            if (p.symmetry !== '1_555') {
                                allId = false;
                                break;
                            }
                        }
                        if (allId) {
                            var _loop_1 = function (opIndex, __oi) {
                                var allMapped = true;
                                for (var _i = 0, _a = e.partners; _i < _a.length; _i++) {
                                    var p = _a[_i];
                                    if (!transformMap.get(p.residueIndex).has(opIndex)) {
                                        allMapped = false;
                                        break;
                                    }
                                }
                                if (!allMapped)
                                    return "continue";
                                ret.push({
                                    bondType: e.bondType,
                                    distance: e.distance,
                                    partners: e.partners.map(function (p) {
                                        var rI = transformMap.get(p.residueIndex).get(opIndex);
                                        return {
                                            residueIndex: rI,
                                            atomIndex: newStart[rI] + (p.atomIndex - oldStart[p.residueIndex]),
                                            symmetry: p.symmetry
                                        };
                                    })
                                });
                            };
                            for (var opIndex = 0, __oi = ops.length; opIndex < __oi; opIndex++) {
                                _loop_1(opIndex, __oi);
                            }
                        }
                        else {
                            var partners = [];
                            for (var _f = 0, _g = e.partners; _f < _g.length; _f++) {
                                var p = _g[_f];
                                if (!opsMap.has(p.symmetry))
                                    break;
                                var op = opsMap.get(p.symmetry);
                                var m = transformMap.get(p.residueIndex);
                                if (!m.has(op))
                                    break;
                                var rI = m.get(op);
                                partners.push({
                                    residueIndex: rI,
                                    atomIndex: newStart[rI] + (p.atomIndex - oldStart[p.residueIndex]),
                                    symmetry: p.symmetry
                                });
                            }
                            if (partners.length === e.partners.length) {
                                ret.push({
                                    bondType: e.bondType,
                                    distance: e.distance,
                                    partners: partners
                                });
                            }
                        }
                    }
                    return new Structure.StructConn(ret);
                }
                function buildSS(parent, assemblyParts, newResidues) {
                    var index = parent.data.residues.secondaryStructureIndex;
                    var ss = parent.data.secondaryStructure;
                    var asymId = newResidues.asymId, seqNumber = newResidues.seqNumber, insCode = newResidues.insCode, secondaryStructureIndex = newResidues.secondaryStructureIndex;
                    var residues = assemblyParts.residues, operators = assemblyParts.operators;
                    var count = residues.length;
                    var ret = [];
                    var start = 0;
                    while (start < count) {
                        var end = start;
                        var ssI = index[residues[start]], op = operators[start];
                        while (end < count && operators[end] == op && index[residues[end]] == ssI)
                            end++;
                        var s = ss[ssI];
                        var e = new Structure.SecondaryStructureElement(s.type, new Structure.PolyResidueIdentifier(asymId[start], seqNumber[start], insCode[start]), new Structure.PolyResidueIdentifier(asymId[end - 1], seqNumber[end - 1], insCode[end - 1]), s.info);
                        e.startResidueIndex = start;
                        e.endResidueIndex = end;
                        var updatedSSI = ret.length;
                        for (var i = start; i < end; i++) {
                            secondaryStructureIndex[i] = updatedSSI;
                        }
                        ret[updatedSSI] = e;
                        start = end;
                    }
                    return ret;
                }
                function buildPivotGroupSymmetry(model, radius, pivotsQuery) {
                    var info = model.data.symmetryInfo;
                    if (!info || (info.cellSize[0] < 1.1 && info.cellSize[1] < 1.1 && info.cellSize[2] < 1.1)) {
                        return model;
                    }
                    var pivotIndices;
                    if (!pivotsQuery)
                        pivotIndices = model.data.atoms.indices;
                    else
                        pivotIndices = Structure.Query.apply(pivotsQuery, model).unionAtomIndices();
                    var bounds = getBoundingInfo(model, pivotIndices), spacegroup = new Structure.Spacegroup(info), ctx = createSymmetryContext(model, bounds, spacegroup, radius);
                    var transforms = findSuitableTransforms(ctx), residues = getSymmetryResidues(ctx, transforms);
                    return assemble(model, residues, transforms);
                }
                SymmetryHelpers.buildPivotGroupSymmetry = buildPivotGroupSymmetry;
                function findMates(model, radius) {
                    var bounds = getBoudingSphere(model.positions, model.positions.indices);
                    var spacegroup = new Structure.Spacegroup(model.data.symmetryInfo);
                    var t = Mat4.zero();
                    var v = Vec3.zero();
                    var transforms = [];
                    for (var i = -3; i <= 3; i++) {
                        for (var j = -3; j <= 3; j++) {
                            for (var k = -3; k <= 3; k++) {
                                for (var op = 0; op < spacegroup.operatorCount; op++) {
                                    spacegroup.getOperatorMatrix(op, i, j, k, t);
                                    Vec3.transformMat4(v, bounds.center, t);
                                    if (getSphereDist(v, bounds.radius, bounds) > radius)
                                        continue;
                                    var copy = Mat4.zero();
                                    Mat4.copy(copy, t);
                                    transforms.push(createSymmetryTransform(i, j, k, op, copy));
                                }
                            }
                        }
                    }
                    return transforms;
                }
                function findMateParts(model, transforms) {
                    var _a = model.data, atoms = _a.atoms, chains = _a.chains, entities = _a.entities, residues = _a.residues;
                    var residueIndices = Core.Utils.ArrayBuilder.create(function (s) { return new Int32Array(s); }, residues.count * transforms.length, 1), operatorIndices = Core.Utils.ArrayBuilder.create(function (s) { return new Int32Array(s); }, residues.count * transforms.length, 1);
                    var atomCount = transforms.length * atoms.count;
                    var chainCount = transforms.length * chains.count;
                    var entityCount = entities.count;
                    for (var eI = 0, _eC = entities.count; eI < _eC; eI++) {
                        for (var opIndex = 0; opIndex < transforms.length; opIndex++) {
                            for (var cI = entities.chainStartIndex[eI], _cC = entities.chainEndIndex[eI]; cI < _cC; cI++) {
                                for (var rI = chains.residueStartIndex[cI], _rC = chains.residueEndIndex[cI]; rI < _rC; rI++) {
                                    Core.Utils.ArrayBuilder.add(residueIndices, rI);
                                    Core.Utils.ArrayBuilder.add(operatorIndices, opIndex);
                                }
                            }
                        }
                    }
                    return {
                        residues: residueIndices.array,
                        operators: operatorIndices.array,
                        atomCount: atomCount,
                        chainCount: chainCount,
                        entityCount: entityCount
                    };
                }
                function buildMates(model, radius) {
                    var info = model.data.symmetryInfo;
                    if (!info || (info.cellSize[0] < 1.1 && info.cellSize[1] < 1.1 && info.cellSize[2] < 1.1)) {
                        return model;
                    }
                    var transforms = findMates(model, radius);
                    var parts = findMateParts(model, transforms);
                    return assemble(model, parts, transforms);
                }
                SymmetryHelpers.buildMates = buildMates;
                function createOperators(operators, list, i, current) {
                    if (i < 0) {
                        list[list.length] = current.slice(0);
                        return;
                    }
                    var ops = operators[i], len = ops.length;
                    for (var j = 0; j < len; j++) {
                        current[i] = ops[j];
                        createOperators(operators, list, i - 1, current);
                    }
                }
                function getAssemblyTransforms(model, operators, offset) {
                    var info = model.data.assemblyInfo;
                    var transforms = [];
                    var index = offset;
                    for (var _i = 0, operators_1 = operators; _i < operators_1.length; _i++) {
                        var op = operators_1[_i];
                        var m = Mat4.identity();
                        for (var i = 0; i < op.length; i++) {
                            Mat4.mul(m, m, info.operators[op[i]].operator);
                        }
                        index++;
                        transforms[transforms.length] = createAssemblyTransform(index, m);
                    }
                    return transforms;
                }
                function getAssemblyParts(model, residueMask, currentTransforms, state, transformOffset) {
                    var _a = model.data, chains = _a.chains, entities = _a.entities, residues = _a.residues;
                    var residueIndices = state.residueIndices, operatorIndices = state.operatorIndices;
                    var atomCount = 0, chainCount = 0, entityCount = 0;
                    for (var eI = 0, _eC = entities.count; eI < _eC; eI++) {
                        var opIndex = transformOffset;
                        var chainAdded = false;
                        for (var _i = 0, currentTransforms_1 = currentTransforms; _i < currentTransforms_1.length; _i++) {
                            var _ = currentTransforms_1[_i];
                            for (var cI = entities.chainStartIndex[eI], _cC = entities.chainEndIndex[eI]; cI < _cC; cI++) {
                                var residueAdded = false;
                                for (var rI = chains.residueStartIndex[cI], _rC = chains.residueEndIndex[cI]; rI < _rC; rI++) {
                                    if (!residueMask[rI])
                                        continue;
                                    Core.Utils.ChunkedArray.add(residueIndices, rI);
                                    Core.Utils.ChunkedArray.add(operatorIndices, opIndex);
                                    atomCount += residues.atomEndIndex[rI] - residues.atomStartIndex[rI];
                                    residueAdded = true;
                                }
                                if (residueAdded) {
                                    chainCount += 1;
                                    chainAdded = true;
                                }
                            }
                            opIndex++;
                        }
                        if (chainAdded) {
                            entityCount++;
                        }
                    }
                    state.atomCount += atomCount;
                    state.chainCount += chainCount;
                    state.entityCount += entityCount;
                }
                function buildAssemblyEntry(model, entry, state) {
                    var _a;
                    var ops = [], currentOp = [];
                    for (var i_2 = 0; i_2 < entry.operators.length; i_2++)
                        currentOp[i_2] = '';
                    createOperators(entry.operators, ops, entry.operators.length - 1, currentOp);
                    var transformOffset = state.transforms.length;
                    var transforms = getAssemblyTransforms(model, ops, state.transforms.length);
                    (_a = state.transforms).push.apply(_a, transforms);
                    var asymIds = Core.Utils.FastSet.create();
                    entry.asymIds.forEach(function (id) { return asymIds.add(id); });
                    var residueAsymIds = model.data.residues.asymId;
                    var residueCount = model.data.residues.count;
                    var mask = state.mask;
                    for (var i = 0; i < residueCount; i++) {
                        mask[i] = asymIds.has(residueAsymIds[i]);
                    }
                    getAssemblyParts(model, mask, transforms, state, transformOffset);
                }
                SymmetryHelpers.buildAssemblyEntry = buildAssemblyEntry;
                function buildAssembly(model, assembly) {
                    var state = {
                        atomCount: 0,
                        chainCount: 0,
                        entityCount: 0,
                        transforms: [],
                        mask: new Int8Array(model.data.residues.count),
                        residueIndices: Core.Utils.ChunkedArray.create(function (s) { return new Int32Array(s); }, model.data.residues.count, 1),
                        operatorIndices: Core.Utils.ChunkedArray.create(function (s) { return new Int32Array(s); }, model.data.residues.count, 1)
                    };
                    for (var _i = 0, _a = assembly.gens; _i < _a.length; _i++) {
                        var a = _a[_i];
                        buildAssemblyEntry(model, a, state);
                    }
                    var parts = {
                        residues: Core.Utils.ChunkedArray.compact(state.residueIndices),
                        operators: Core.Utils.ChunkedArray.compact(state.operatorIndices),
                        atomCount: state.atomCount,
                        chainCount: state.chainCount,
                        entityCount: state.entityCount
                    };
                    return assemble(model, parts, state.transforms);
                }
                SymmetryHelpers.buildAssembly = buildAssembly;
            })(SymmetryHelpers || (SymmetryHelpers = {}));
            function buildPivotGroupSymmetry(model, radius, pivotsQuery) {
                return SymmetryHelpers.buildPivotGroupSymmetry(model, radius, pivotsQuery);
            }
            Structure.buildPivotGroupSymmetry = buildPivotGroupSymmetry;
            function buildSymmetryMates(model, radius) {
                return SymmetryHelpers.buildMates(model, radius);
            }
            Structure.buildSymmetryMates = buildSymmetryMates;
            function buildAssembly(model, assembly) {
                return SymmetryHelpers.buildAssembly(model, assembly);
            }
            Structure.buildAssembly = buildAssembly;
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            var Query;
            (function (Query) {
                function apply(q, m) {
                    return Query.Builder.toQuery(q)(m.queryContext);
                }
                Query.apply = apply;
                /**
                 * The context of a query.
                 *
                 * Stores:
                 * - the mask of "active" atoms.
                 * - kd-tree for fast geometry queries.
                 * - the molecule itself.
                 *
                 */
                var Context = /** @class */ (function () {
                    function Context(structure, mask) {
                        this.mask = mask;
                        this.structure = structure;
                    }
                    Object.defineProperty(Context.prototype, "atomCount", {
                        /**
                         * Number of atoms in the current context.
                         */
                        get: function () {
                            return this.mask.size;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Context.prototype, "isComplete", {
                        /**
                         * Determine if the context contains all atoms of the input model.
                         */
                        get: function () {
                            return this.mask.size === this.structure.data.atoms.count;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Context.prototype, "lookup3d", {
                        /**
                         * Get a 3d loopup structure for the atoms in the current context.
                         */
                        get: function () {
                            if (!this.lazyLoopup3d)
                                this.makeLookup3d();
                            return this.lazyLoopup3d;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    /**
                     * Checks if an atom is included in the current context.
                     */
                    Context.prototype.hasAtom = function (index) {
                        return !!this.mask.has(index);
                    };
                    /**
                     * Checks if an atom from the range is included in the current context.
                     */
                    Context.prototype.hasRange = function (start, end) {
                        for (var i = start; i < end; i++) {
                            if (this.mask.has(i))
                                return true;
                        }
                        return false;
                    };
                    /**
                     * Create a new context based on the provide structure.
                     */
                    Context.ofStructure = function (structure) {
                        return new Context(structure, Core.Utils.Mask.ofStructure(structure));
                    };
                    /**
                     * Create a new context from a sequence of fragments.
                     */
                    Context.ofFragments = function (seq) {
                        return new Context(seq.context.structure, Core.Utils.Mask.ofFragments(seq));
                    };
                    /**
                     * Create a new context from a sequence of fragments.
                     */
                    Context.ofAtomIndices = function (structure, atomIndices) {
                        return new Context(structure, Core.Utils.Mask.ofIndices(structure.data.atoms.count, atomIndices));
                    };
                    Context.prototype.makeLookup3d = function () {
                        var data = new Int32Array(this.mask.size), dataCount = 0, _a = this.structure.positions, x = _a.x, y = _a.y, z = _a.z;
                        for (var i = 0, _b = this.structure.positions.count; i < _b; i++) {
                            if (this.mask.has(i))
                                data[dataCount++] = i;
                        }
                        var inputData = Core.Geometry.Query3D.createInputData(data, function (i, add) { return add(x[i], y[i], z[i]); });
                        this.lazyLoopup3d = Core.Geometry.Query3D.createSpatialHash(inputData);
                    };
                    return Context;
                }());
                Query.Context = Context;
                /**
                 * The basic element of the query language.
                 * Everything is represented as a fragment.
                 */
                var Fragment = /** @class */ (function () {
                    /**
                     * Create a fragment from an integer set.
                     */
                    function Fragment(context, tag, atomIndices) {
                        this._hashCode = 0;
                        this._hashComputed = false;
                        this.context = context;
                        this.tag = tag;
                        this.atomIndices = atomIndices;
                    }
                    Object.defineProperty(Fragment.prototype, "hashCode", {
                        /**
                         * The hash code of the fragment.
                         */
                        get: function () {
                            if (this._hashComputed)
                                return this._hashCode;
                            var code = 23;
                            for (var _i = 0, _a = this.atomIndices; _i < _a.length; _i++) {
                                var i = _a[_i];
                                code = (31 * code + i) | 0;
                            }
                            this._hashCode = code;
                            this._hashComputed = true;
                            return code;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "id", {
                        /**
                         * Id composed of <moleculeid>_<tag>.
                         */
                        get: function () {
                            return this.context.structure.id + "_" + this.tag;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "atomCount", {
                        /**
                         * Number of atoms.
                         */
                        get: function () {
                            return this.atomIndices.length;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "isHet", {
                        /**
                         * Determines if a fragment is HET based on the tag.
                         */
                        get: function () {
                            var residue = this.context.structure.data.atoms.residueIndex[this.tag];
                            return this.context.structure.data.residues.isHet[residue];
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "fingerprint", {
                        /**
                         * A sorted list of residue identifiers.
                         */
                        get: function () {
                            if (this._fingerprint)
                                return this._fingerprint;
                            var indexList = this.residueIndices, residues = this.context.structure.data.residues, cName = residues.name, cAsym = residues.asymId, cSeq = residues.seqNumber, insCode = residues.insCode, names = [];
                            for (var _i = 0, indexList_1 = indexList; _i < indexList_1.length; _i++) {
                                var i = indexList_1[_i];
                                var name_1 = cName[i] + " " + cAsym[i] + " " + cSeq[i];
                                if (insCode[i])
                                    name_1 += " i:" + insCode[i];
                                names[names.length] = name_1;
                            }
                            return names.join("-");
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "authFingerprint", {
                        /**
                         * A sorted list of residue identifiers.
                         */
                        get: function () {
                            if (this._authFingerprint)
                                return this._authFingerprint;
                            var indexList = this.residueIndices, residues = this.context.structure.data.residues, cName = residues.authName, cAsym = residues.authAsymId, cSeq = residues.authSeqNumber, insCode = residues.insCode, names = [];
                            for (var _i = 0, indexList_2 = indexList; _i < indexList_2.length; _i++) {
                                var i = indexList_2[_i];
                                var name_2 = cName[i] + " " + cAsym[i] + " " + cSeq[i];
                                if (insCode[i])
                                    name_2 += " i:" + insCode[i];
                                names[names.length] = name_2;
                            }
                            return names.join("-");
                        },
                        enumerable: true,
                        configurable: true
                    });
                    /**
                     * Executes a query on the current fragment.
                     */
                    Fragment.prototype.find = function (what) {
                        var ctx = Context.ofFragments(new FragmentSeq(this.context, [this]));
                        return Query.Builder.toQuery(what)(ctx);
                    };
                    Fragment.prototype.computeIndices = function () {
                        if (this._residueIndices)
                            return;
                        var residueIndices = Core.Utils.FastSet.create(), chainIndices = Core.Utils.FastSet.create(), entityIndices = Core.Utils.FastSet.create(), rIndices = this.context.structure.data.atoms.residueIndex, cIndices = this.context.structure.data.residues.chainIndex, eIndices = this.context.structure.data.chains.entityIndex;
                        for (var _i = 0, _a = this.atomIndices; _i < _a.length; _i++) {
                            var i = _a[_i];
                            residueIndices.add(rIndices[i]);
                        }
                        this._residueIndices = Core.Utils.integerSetToSortedTypedArray(residueIndices);
                        for (var _c = 0, _d = this._residueIndices; _c < _d.length; _c++) {
                            var i = _d[_c];
                            chainIndices.add(cIndices[i]);
                        }
                        this._chainIndices = Core.Utils.integerSetToSortedTypedArray(chainIndices);
                        for (var _e = 0, _f = this._chainIndices; _e < _f.length; _e++) {
                            var i = _f[_e];
                            entityIndices.add(eIndices[i]);
                        }
                        this._entityIndices = Core.Utils.integerSetToSortedTypedArray(entityIndices);
                    };
                    Object.defineProperty(Fragment.prototype, "residueIndices", {
                        /**
                         * A sorted list of residue indices.
                         */
                        get: function () {
                            this.computeIndices();
                            return this._residueIndices;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "chainIndices", {
                        /**
                         * A sorted list of chain indices.
                         */
                        get: function () {
                            this.computeIndices();
                            return this._chainIndices;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(Fragment.prototype, "entityIndices", {
                        /**
                         * A sorted list of entity indices.
                         */
                        get: function () {
                            this.computeIndices();
                            return this._entityIndices;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Fragment.areEqual = function (a, b) {
                        if (a.atomCount !== b.atomCount)
                            return false;
                        var xs = a.atomIndices, ys = b.atomIndices;
                        for (var i = 0; i < xs.length; i++) {
                            if (xs[i] !== ys[i])
                                return false;
                        }
                        return a.tag === b.tag;
                    };
                    /**
                     * Create a fragment from an integer set.
                     * Assumes the set is in the given context's mask.
                     */
                    Fragment.ofSet = function (context, atomIndices) {
                        var array = new Int32Array(atomIndices.size);
                        atomIndices.forEach(function (i, ctx) { ctx.array[ctx.index++] = i; }, { array: array, index: 0 });
                        Array.prototype.sort.call(array, function (a, b) { return a - b; });
                        return new Fragment(context, array[0], array);
                    };
                    /**
                     * Create a fragment from an integer array.
                     * Assumes the set is in the given context's mask.
                     * Assumes the array is sorted.
                     */
                    Fragment.ofArray = function (context, tag, atomIndices) {
                        return new Fragment(context, tag, atomIndices);
                    };
                    /**
                     * Create a fragment from a single index.
                     * Assumes the index is in the given context's mask.
                     */
                    Fragment.ofIndex = function (context, index) {
                        var indices = new Int32Array(1);
                        indices[0] = index;
                        return new Fragment(context, index, indices);
                    };
                    /**
                     * Create a fragment from a <start,end) range.
                     * Assumes the fragment is non-empty in the given context's mask.
                     */
                    Fragment.ofIndexRange = function (context, start, endExclusive) {
                        var count = 0;
                        for (var i = start; i < endExclusive; i++) {
                            if (context.hasAtom(i))
                                count++;
                        }
                        var atoms = new Int32Array(count), offset = 0;
                        for (var i = start; i < endExclusive; i++) {
                            if (context.hasAtom(i))
                                atoms[offset++] = i;
                        }
                        return new Fragment(context, start, atoms);
                    };
                    return Fragment;
                }());
                Query.Fragment = Fragment;
                /**
                 * A sequence of fragments the queries operate on.
                 */
                var FragmentSeq = /** @class */ (function () {
                    function FragmentSeq(context, fragments) {
                        this.context = context;
                        this.fragments = fragments;
                    }
                    FragmentSeq.empty = function (ctx) {
                        return new FragmentSeq(ctx, []);
                    };
                    Object.defineProperty(FragmentSeq.prototype, "length", {
                        get: function () {
                            return this.fragments.length;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    /**
                     * Merges atom indices from all fragments.
                     */
                    FragmentSeq.prototype.unionAtomIndices = function () {
                        if (!this.length)
                            return [];
                        if (this.length === 1)
                            return this.fragments[0].atomIndices;
                        var map = new Int8Array(this.context.structure.data.atoms.count), atomCount = 0;
                        for (var _i = 0, _a = this.fragments; _i < _a.length; _i++) {
                            var f = _a[_i];
                            for (var _c = 0, _d = f.atomIndices; _c < _d.length; _c++) {
                                var i = _d[_c];
                                map[i] = 1;
                            }
                        }
                        for (var _e = 0, map_1 = map; _e < map_1.length; _e++) {
                            var i = map_1[_e];
                            atomCount += i;
                        }
                        var ret = new Int32Array(atomCount), offset = 0;
                        for (var i = 0, _l = map.length; i < _l; i++) {
                            if (map[i])
                                ret[offset++] = i;
                        }
                        return ret;
                    };
                    /**
                     * Merges atom indices from all fragments into a single fragment.
                     */
                    FragmentSeq.prototype.unionFragment = function () {
                        if (!this.length)
                            return new Fragment(this.context, 0, new Int32Array(0));
                        if (this.length === 1)
                            return this.fragments[0];
                        var union = this.unionAtomIndices();
                        return new Fragment(this.context, union[0], union);
                    };
                    return FragmentSeq;
                }());
                Query.FragmentSeq = FragmentSeq;
                /**
                 * A builder that includes all fragments.
                 */
                var FragmentSeqBuilder = /** @class */ (function () {
                    function FragmentSeqBuilder(ctx) {
                        this.ctx = ctx;
                        this.fragments = [];
                    }
                    FragmentSeqBuilder.prototype.add = function (f) {
                        this.fragments[this.fragments.length] = f;
                    };
                    FragmentSeqBuilder.prototype.getSeq = function () {
                        return new FragmentSeq(this.ctx, this.fragments);
                    };
                    return FragmentSeqBuilder;
                }());
                Query.FragmentSeqBuilder = FragmentSeqBuilder;
                /**
                 * A builder that includes only unique fragments.
                 */
                var HashFragmentSeqBuilder = /** @class */ (function () {
                    function HashFragmentSeqBuilder(ctx) {
                        this.ctx = ctx;
                        this.fragments = [];
                        this.byHash = Core.Utils.FastMap.create();
                    }
                    HashFragmentSeqBuilder.prototype.add = function (f) {
                        var hash = f.hashCode;
                        if (this.byHash.has(hash)) {
                            var fs = this.byHash.get(hash);
                            for (var _i = 0, fs_1 = fs; _i < fs_1.length; _i++) {
                                var q = fs_1[_i];
                                if (Fragment.areEqual(f, q))
                                    return this;
                            }
                            this.fragments[this.fragments.length] = f;
                            fs[fs.length] = f;
                        }
                        else {
                            this.fragments[this.fragments.length] = f;
                            this.byHash.set(hash, [f]);
                        }
                        return this;
                    };
                    HashFragmentSeqBuilder.prototype.getSeq = function () {
                        return new FragmentSeq(this.ctx, this.fragments);
                    };
                    return HashFragmentSeqBuilder;
                }());
                Query.HashFragmentSeqBuilder = HashFragmentSeqBuilder;
            })(Query = Structure.Query || (Structure.Query = {}));
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            var Query;
            (function (Query) {
                var Builder;
                (function (Builder) {
                    Builder.BuilderPrototype = {};
                    function registerModifier(name, f) {
                        Builder.BuilderPrototype[name] = function () {
                            var args = [];
                            for (var _i = 0; _i < arguments.length; _i++) {
                                args[_i] = arguments[_i];
                            }
                            return f.call.apply(f, [void 0, this].concat(args));
                        };
                    }
                    Builder.registerModifier = registerModifier;
                    function build(compile) {
                        return Object.create(Builder.BuilderPrototype, { compile: { writable: false, configurable: false, value: compile } });
                    }
                    Builder.build = build;
                    function isBuilder(e) {
                        return !!e.compile;
                    }
                    function parse(query) {
                        if (typeof window === 'undefined')
                            throw 'parse can only be called from a browser.';
                        (function () { }(), eval)("with (LiteMol.Core.Structure.Query) { window.__LiteMol_query = " + query + "; }");
                        var q = window.__LiteMol_query;
                        window.__LiteMol_query = void 0;
                        return q.compile();
                    }
                    Builder.parse = parse;
                    function toQuery(q) {
                        var ret;
                        if (isBuilder(q))
                            ret = q.compile();
                        else if (typeof q === 'string' || q instanceof String)
                            ret = parse(q);
                        else
                            ret = q;
                        return ret;
                    }
                    Builder.toQuery = toQuery;
                })(Builder = Query.Builder || (Query.Builder = {}));
                function allAtoms() { return Builder.build(function () { return Compiler.compileAllAtoms(); }); }
                Query.allAtoms = allAtoms;
                function atomsByElement() {
                    var elements = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        elements[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtoms(elements, function (m) { return m.data.atoms.elementSymbol; }); });
                }
                Query.atomsByElement = atomsByElement;
                function atomsByName() {
                    var names = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        names[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtoms(names, function (m) { return m.data.atoms.name; }); });
                }
                Query.atomsByName = atomsByName;
                function atomsById() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtoms(ids, function (m) { return m.data.atoms.id; }); });
                }
                Query.atomsById = atomsById;
                function residues() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtomRanges(false, ids, function (m) { return m.data.residues; }); });
                }
                Query.residues = residues;
                function chains() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtomRanges(false, ids, function (m) { return m.data.chains; }); });
                }
                Query.chains = chains;
                function entities() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtomRanges(false, ids, function (m) { return m.data.entities; }); });
                }
                Query.entities = entities;
                function notEntities() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileAtomRanges(true, ids, function (m) { return m.data.entities; }); });
                }
                Query.notEntities = notEntities;
                function everything() { return Builder.build(function () { return Compiler.compileEverything(); }); }
                Query.everything = everything;
                function entitiesFromIndices(indices) { return Builder.build(function () { return Compiler.compileFromIndices(false, indices, function (m) { return m.data.entities; }); }); }
                Query.entitiesFromIndices = entitiesFromIndices;
                function chainsFromIndices(indices) { return Builder.build(function () { return Compiler.compileFromIndices(false, indices, function (m) { return m.data.chains; }); }); }
                Query.chainsFromIndices = chainsFromIndices;
                function residuesFromIndices(indices) { return Builder.build(function () { return Compiler.compileFromIndices(false, indices, function (m) { return m.data.residues; }); }); }
                Query.residuesFromIndices = residuesFromIndices;
                function atomsFromIndices(indices) { return Builder.build(function () { return Compiler.compileAtomIndices(indices); }); }
                Query.atomsFromIndices = atomsFromIndices;
                function sequence(entityId, asymId, startId, endId) { return Builder.build(function () { return Compiler.compileSequence(entityId, asymId, startId, endId); }); }
                Query.sequence = sequence;
                function hetGroups() { return Builder.build(function () { return Compiler.compileHetGroups(); }); }
                Query.hetGroups = hetGroups;
                function nonHetPolymer() { return Builder.build(function () { return Compiler.compileNonHetPolymer(); }); }
                Query.nonHetPolymer = nonHetPolymer;
                function polymerTrace() {
                    var atomNames = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        atomNames[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compilePolymerNames(atomNames, false); });
                }
                Query.polymerTrace = polymerTrace;
                function cartoons() { return or(Builder.build(function () { return Compiler.compilePolymerNames(["CA", "O", "O5'", "C3'", "N3"], false); }), hetGroups(), entities({ type: 'water' })); }
                Query.cartoons = cartoons;
                function backbone() { return Builder.build(function () { return Compiler.compilePolymerNames(["N", "CA", "C", "O", "P", "OP1", "OP2", "O3'", "O5'", "C3'", "C5'", "C4"], false); }); }
                Query.backbone = backbone;
                function sidechain() { return Builder.build(function () { return Compiler.compilePolymerNames(["N", "CA", "C", "O", "P", "OP1", "OP2", "O3'", "O5'", "C3'", "C5'", "C4"], true); }); }
                Query.sidechain = sidechain;
                function atomsInBox(min, max) { return Builder.build(function () { return Compiler.compileAtomsInBox(min, max); }); }
                Query.atomsInBox = atomsInBox;
                function or() {
                    var elements = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        elements[_i] = arguments[_i];
                    }
                    return Builder.build(function () { return Compiler.compileOr(elements); });
                }
                Query.or = or;
                Builder.registerModifier('complement', complement);
                function complement(q) { return Builder.build(function () { return Compiler.compileComplement(q); }); }
                Query.complement = complement;
                Builder.registerModifier('ambientResidues', ambientResidues);
                function ambientResidues(q, radius) { return Builder.build(function () { return Compiler.compileAmbientResidues(q, radius); }); }
                Query.ambientResidues = ambientResidues;
                Builder.registerModifier('wholeResidues', wholeResidues);
                function wholeResidues(q) { return Builder.build(function () { return Compiler.compileWholeResidues(q); }); }
                Query.wholeResidues = wholeResidues;
                Builder.registerModifier('union', union);
                function union(q) { return Builder.build(function () { return Compiler.compileUnion(q); }); }
                Query.union = union;
                Builder.registerModifier('inside', inside);
                function inside(q, where) { return Builder.build(function () { return Compiler.compileInside(q, where); }); }
                Query.inside = inside;
                Builder.registerModifier('intersectWith', intersectWith);
                function intersectWith(what, where) { return Builder.build(function () { return Compiler.compileIntersectWith(what, where); }); }
                Query.intersectWith = intersectWith;
                Builder.registerModifier('flatten', flatten);
                function flatten(what, selector) { return Builder.build(function () { return Compiler.compileFlatten(what, selector); }); }
                Query.flatten = flatten;
                Builder.registerModifier('except', except);
                function except(what, toRemove) { return Builder.build(function () { return Compiler.compileExcept(what, toRemove); }); }
                Query.except = except;
                /**
                 * Shortcuts
                 */
                function residuesByName() {
                    var names = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        names[_i] = arguments[_i];
                    }
                    return residues.apply(void 0, names.map(function (n) { return ({ name: n }); }));
                }
                Query.residuesByName = residuesByName;
                function residuesById() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return residues.apply(void 0, ids.map(function (id) { return ({ authSeqNumber: id }); }));
                }
                Query.residuesById = residuesById;
                function chainsById() {
                    var ids = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        ids[_i] = arguments[_i];
                    }
                    return chains.apply(void 0, ids.map(function (id) { return ({ authAsymId: id }); }));
                }
                Query.chainsById = chainsById;
                /**
                 * Query compilation wrapper.
                 */
                var Compiler;
                (function (Compiler) {
                    var OptimizedId = /** @class */ (function () {
                        function OptimizedId(id, arrays) {
                            this.columns = [];
                            for (var _i = 0, _a = Object.keys(id); _i < _a.length; _i++) {
                                var key = _a[_i];
                                if (id[key] !== void 0 && !!arrays[key]) {
                                    this.columns.push({ value: id[key], array: arrays[key] });
                                }
                            }
                        }
                        OptimizedId.prototype.isSatisfied = function (i) {
                            for (var _i = 0, _a = this.columns; _i < _a.length; _i++) {
                                var c = _a[_i];
                                if (c.value !== c.array[i])
                                    return false;
                            }
                            return true;
                        };
                        return OptimizedId;
                    }());
                    function compileEverything() {
                        return function (ctx) {
                            if (ctx.isComplete) {
                                var atoms = ctx.structure.data.atoms.indices;
                                return new Query.FragmentSeq(ctx, [new Query.Fragment(ctx, atoms[0], atoms)]);
                            }
                            var indices = new Int32Array(ctx.atomCount);
                            var offset = 0;
                            for (var _i = 0, _a = ctx.structure.data.atoms.indices; _i < _a.length; _i++) {
                                var i = _a[_i];
                                if (ctx.hasAtom(i))
                                    indices[offset++] = i;
                            }
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, indices[0], indices)]);
                        };
                    }
                    Compiler.compileEverything = compileEverything;
                    function compileAllAtoms() {
                        return function (ctx) {
                            var fragments = new Query.FragmentSeqBuilder(ctx);
                            for (var i = 0, _b = ctx.structure.data.atoms.count; i < _b; i++) {
                                if (ctx.hasAtom(i))
                                    fragments.add(Query.Fragment.ofIndex(ctx, i));
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileAllAtoms = compileAllAtoms;
                    function compileAtoms(elements, sel) {
                        return function (ctx) {
                            var set = Core.Utils.FastSet.ofArray(elements), data = sel(ctx.structure), fragments = new Query.FragmentSeqBuilder(ctx);
                            for (var i = 0, _b = data.length; i < _b; i++) {
                                if (ctx.hasAtom(i) && set.has(data[i]))
                                    fragments.add(Query.Fragment.ofIndex(ctx, i));
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileAtoms = compileAtoms;
                    function compileAtomIndices(indices) {
                        return function (ctx) {
                            var count = 0;
                            for (var _i = 0, indices_5 = indices; _i < indices_5.length; _i++) {
                                var aI = indices_5[_i];
                                if (ctx.hasAtom(aI))
                                    count++;
                            }
                            if (!count)
                                return Query.FragmentSeq.empty(ctx);
                            if (count === indices.length)
                                return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, indices[0], indices)]);
                            var offset = 0;
                            var f = new Int32Array(count);
                            for (var _a = 0, indices_6 = indices; _a < indices_6.length; _a++) {
                                var aI = indices_6[_a];
                                if (ctx.hasAtom(aI))
                                    f[offset++] = aI;
                            }
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, f[0], f)]);
                        };
                    }
                    Compiler.compileAtomIndices = compileAtomIndices;
                    function compileFromIndices(complement, indices, tableProvider) {
                        return function (ctx) {
                            var table = tableProvider(ctx.structure), atomStartIndex = table.atomStartIndex, atomEndIndex = table.atomEndIndex, fragments = new Query.FragmentSeqBuilder(ctx);
                            if (complement) {
                                var exclude = Core.Utils.FastSet.ofArray(indices);
                                var count = table.count;
                                for (var i = 0; i < count; i++) {
                                    if (exclude.has(i))
                                        continue;
                                    if (!ctx.hasRange(atomStartIndex[i], atomEndIndex[i]))
                                        continue;
                                    fragments.add(Query.Fragment.ofIndexRange(ctx, atomStartIndex[i], atomEndIndex[i]));
                                }
                            }
                            else {
                                for (var _i = 0, indices_7 = indices; _i < indices_7.length; _i++) {
                                    var i = indices_7[_i];
                                    if (!ctx.hasRange(atomStartIndex[i], atomEndIndex[i]))
                                        continue;
                                    fragments.add(Query.Fragment.ofIndexRange(ctx, atomStartIndex[i], atomEndIndex[i]));
                                }
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileFromIndices = compileFromIndices;
                    function compileAtomRanges(complement, ids, tableProvider) {
                        return function (ctx) {
                            var table = tableProvider(ctx.structure), atomIndexStart = table.atomStartIndex, atomIndexEnd = table.atomEndIndex, fragments = new Query.FragmentSeqBuilder(ctx), count = table.count, include = false;
                            var optimized = ids.map(function (id) { return new OptimizedId(id, table); });
                            var isEmptyIds = optimized.length === 0;
                            for (var i = 0; i < count; i++) {
                                if (!ctx.hasRange(atomIndexStart[i], atomIndexEnd[i]))
                                    continue;
                                include = isEmptyIds;
                                for (var _i = 0, optimized_1 = optimized; _i < optimized_1.length; _i++) {
                                    var id = optimized_1[_i];
                                    if (id.isSatisfied(i)) {
                                        include = true;
                                        break;
                                    }
                                }
                                if (complement)
                                    include = !include;
                                if (include) {
                                    fragments.add(Query.Fragment.ofIndexRange(ctx, atomIndexStart[i], atomIndexEnd[i]));
                                }
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileAtomRanges = compileAtomRanges;
                    function compileSequence(seqEntityId, seqAsymId, start, end) {
                        return function (ctx) {
                            var _a = ctx.structure.data, residues = _a.residues, chains = _a.chains, seqNumber = residues.seqNumber, atomStartIndex = residues.atomStartIndex, atomEndIndex = residues.atomEndIndex, entityId = chains.entityId, count = chains.count, residueStartIndex = chains.residueStartIndex, residueEndIndex = chains.residueEndIndex, fragments = new Query.FragmentSeqBuilder(ctx);
                            var parent = ctx.structure.parent, sourceChainIndex = chains.sourceChainIndex, isComputed = parent && sourceChainIndex;
                            var targetAsymId = typeof seqAsymId === 'string' ? { asymId: seqAsymId } : seqAsymId;
                            var optTargetAsymId = new OptimizedId(targetAsymId, isComputed ? parent.data.chains : chains);
                            //optAsymId.isSatisfied();
                            for (var cI = 0; cI < count; cI++) {
                                if (entityId[cI] !== seqEntityId
                                    || !optTargetAsymId.isSatisfied(isComputed ? sourceChainIndex[cI] : cI)) {
                                    continue;
                                }
                                var i = residueStartIndex[cI], last = residueEndIndex[cI], startIndex = -1, endIndex = -1;
                                for (; i < last; i++) {
                                    if (seqNumber[i] >= start.seqNumber) {
                                        startIndex = i;
                                        break;
                                    }
                                }
                                if (i === last)
                                    continue;
                                for (i = startIndex; i < last; i++) {
                                    if (seqNumber[i] >= end.seqNumber) {
                                        break;
                                    }
                                }
                                endIndex = i;
                                if (ctx.hasRange(atomStartIndex[startIndex], atomEndIndex[endIndex])) {
                                    fragments.add(Query.Fragment.ofIndexRange(ctx, atomStartIndex[startIndex], atomEndIndex[endIndex]));
                                }
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileSequence = compileSequence;
                    function compileHetGroups() {
                        return function (ctx) {
                            var _a = ctx.structure.data.residues, atomStartIndex = _a.atomStartIndex, atomEndIndex = _a.atomEndIndex, isHet = _a.isHet, entityIndex = _a.entityIndex, count = _a.count, entityType = ctx.structure.data.entities.type, water = 'water', fragments = new Query.FragmentSeqBuilder(ctx);
                            for (var i = 0; i < count; i++) {
                                if (!ctx.hasRange(atomStartIndex[i], atomEndIndex[i]))
                                    continue;
                                if (entityType[entityIndex[i]] === water)
                                    continue;
                                if (isHet[i]) {
                                    fragments.add(Query.Fragment.ofIndexRange(ctx, atomStartIndex[i], atomEndIndex[i]));
                                }
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileHetGroups = compileHetGroups;
                    function compileNonHetPolymer() {
                        return function (ctx) {
                            var _a = ctx.structure.data.residues, atomStartIndex = _a.atomStartIndex, atomEndIndex = _a.atomEndIndex, _c = ctx.structure.data.entities, entityType = _c.type, entityCount = _c.count, eRS = _c.residueStartIndex, eRE = _c.residueEndIndex, polymer = 'polymer', size = 0;
                            for (var eI = 0; eI < entityCount; eI++) {
                                if (entityType[eI] !== polymer)
                                    continue;
                                for (var rI = eRS[eI], _bR = eRE[eI]; rI < _bR; rI++) {
                                    for (var aI = atomStartIndex[rI], _bA = atomEndIndex[rI]; aI < _bA; aI++) {
                                        if (ctx.hasAtom(aI))
                                            size++;
                                    }
                                }
                            }
                            if (!size)
                                return Query.FragmentSeq.empty(ctx);
                            var f = new Int32Array(size), offset = 0;
                            for (var eI = 0; eI < entityCount; eI++) {
                                if (entityType[eI] !== polymer)
                                    continue;
                                for (var rI = eRS[eI], _bR = eRE[eI]; rI < _bR; rI++) {
                                    for (var aI = atomStartIndex[rI], _bA = atomEndIndex[rI]; aI < _bA; aI++) {
                                        if (ctx.hasAtom(aI))
                                            f[offset++] = aI;
                                    }
                                }
                            }
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, f[0], f)]);
                        };
                    }
                    Compiler.compileNonHetPolymer = compileNonHetPolymer;
                    function compileAtomsInBox(min, max) {
                        return function (ctx) {
                            var positions = ctx.structure.positions, xs = positions.x, ys = positions.y, zs = positions.z, count = positions.count, fragment = [];
                            for (var i = 0; i < count; i++) {
                                if (!ctx.hasAtom(i))
                                    continue;
                                var x = xs[i], y = ys[i], z = zs[i];
                                if (x >= min.x && x <= max.x
                                    && y >= min.y && y <= max.y
                                    && z >= min.z && z <= max.z) {
                                    fragment[fragment.length] = i;
                                }
                            }
                            if (!fragment.length)
                                return Query.FragmentSeq.empty(ctx);
                            return new Query.FragmentSeq(ctx, [new Query.Fragment(ctx, fragment[0], fragment)]);
                        };
                    }
                    Compiler.compileAtomsInBox = compileAtomsInBox;
                    function compileInside(what, where) {
                        var _what = Builder.toQuery(what);
                        var _where = Builder.toQuery(where);
                        return function (ctx) {
                            return new Query.FragmentSeq(ctx, _what(Query.Context.ofFragments(_where(ctx))).fragments);
                        };
                    }
                    Compiler.compileInside = compileInside;
                    function narrowFragment(ctx, f, m) {
                        var count = 0;
                        for (var _i = 0, _a = f.atomIndices; _i < _a.length; _i++) {
                            var i = _a[_i];
                            if (m.has(i))
                                count++;
                        }
                        if (!count)
                            return void 0;
                        var ret = new Int32Array(count);
                        var offset = 0;
                        for (var _c = 0, _d = f.atomIndices; _c < _d.length; _c++) {
                            var i = _d[_c];
                            if (m.has(i))
                                ret[offset++] = i;
                        }
                        return Query.Fragment.ofArray(ctx, ret[0], ret);
                    }
                    function compileIntersectWith(what, where) {
                        var _what = Builder.toQuery(what);
                        var _where = Builder.toQuery(where);
                        return function (ctx) {
                            var fs = _what(ctx);
                            var map = Core.Utils.Mask.ofFragments(_where(ctx));
                            var ret = new Query.FragmentSeqBuilder(ctx);
                            for (var _i = 0, _a = fs.fragments; _i < _a.length; _i++) {
                                var f = _a[_i];
                                var n = narrowFragment(ctx, f, map);
                                if (n)
                                    ret.add(n);
                            }
                            return ret.getSeq();
                        };
                    }
                    Compiler.compileIntersectWith = compileIntersectWith;
                    function compileFilter(what, filter) {
                        var _what = Builder.toQuery(what);
                        return function (ctx) {
                            var src = _what(ctx).fragments, result = new Query.FragmentSeqBuilder(ctx), f;
                            for (var i = 0; i < src.length; i++) {
                                f = src[i];
                                if (filter(f))
                                    result.add(f);
                            }
                            return result.getSeq();
                        };
                    }
                    Compiler.compileFilter = compileFilter;
                    function compileComplement(what) {
                        var _what = Builder.toQuery(what);
                        return function (ctx) {
                            var mask = Core.Utils.Mask.ofFragments(_what(ctx)), count = 0, offset = 0;
                            for (var i = 0, _b = ctx.structure.data.atoms.count; i < _b; i++) {
                                if (ctx.hasAtom(i) && !mask.has(i))
                                    count++;
                            }
                            if (!count)
                                return Query.FragmentSeq.empty(ctx);
                            var atoms = new Int32Array(count);
                            for (var i = 0, _b = ctx.structure.data.atoms.count; i < _b; i++) {
                                if (ctx.hasAtom(i) && !mask.has(i))
                                    atoms[offset++] = i;
                            }
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, atoms[0], atoms)]);
                        };
                    }
                    Compiler.compileComplement = compileComplement;
                    function compileOr(queries) {
                        var _qs = queries.map(function (q) { return Builder.toQuery(q); });
                        return function (ctx) {
                            var fragments = new Query.HashFragmentSeqBuilder(ctx);
                            for (var _i = 0, _qs_1 = _qs; _i < _qs_1.length; _i++) {
                                var q = _qs_1[_i];
                                var r = q(ctx);
                                for (var _a = 0, _c = r.fragments; _a < _c.length; _a++) {
                                    var f = _c[_a];
                                    fragments.add(f);
                                }
                            }
                            return fragments.getSeq();
                        };
                    }
                    Compiler.compileOr = compileOr;
                    function compileUnion(what) {
                        var _what = Builder.toQuery(what);
                        return function (ctx) {
                            var src = _what(ctx).fragments, indices = Core.Utils.FastSet.create(), j = 0, atoms;
                            for (var i = 0; i < src.length; i++) {
                                atoms = src[i].atomIndices;
                                for (j = 0; j < atoms.length; j++)
                                    indices.add(atoms[j]);
                            }
                            if (indices.size === 0)
                                return Query.FragmentSeq.empty(ctx);
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofSet(ctx, indices)]);
                        };
                    }
                    Compiler.compileUnion = compileUnion;
                    function compilePolymerNames(names, complement) {
                        return function (ctx) {
                            var structure = ctx.structure, entities = structure.data.entities, atomNames = structure.data.atoms.name, indices = [], indexCount = 0;
                            var allowedNames = Core.Utils.FastSet.ofArray(names);
                            if (complement) {
                                for (var ei = 0; ei < structure.data.entities.count; ei++) {
                                    if (entities.type[ei] !== 'polymer')
                                        continue;
                                    var start = entities.atomStartIndex[ei], end = entities.atomEndIndex[ei];
                                    for (var i = start; i < end; i++) {
                                        if (ctx.hasAtom(i) && !allowedNames.has(atomNames[i]))
                                            indices[indexCount++] = i;
                                    }
                                }
                            }
                            else {
                                for (var ei = 0; ei < entities.count; ei++) {
                                    if (entities.type[ei] !== 'polymer')
                                        continue;
                                    var start = entities.atomStartIndex[ei], end = entities.atomEndIndex[ei];
                                    for (var i = start; i < end; i++) {
                                        if (ctx.hasAtom(i) && allowedNames.has(atomNames[i]))
                                            indices[indexCount++] = i;
                                    }
                                }
                            }
                            if (!indices.length)
                                return Query.FragmentSeq.empty(ctx);
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, indices[0], new Int32Array(indices))]);
                        };
                    }
                    Compiler.compilePolymerNames = compilePolymerNames;
                    function compileAmbientResidues(where, radius) {
                        var _where = Builder.toQuery(where);
                        return function (ctx) {
                            var src = _where(ctx), nearest = ctx.lookup3d(), ret = new Query.HashFragmentSeqBuilder(ctx), _a = ctx.structure.positions, x = _a.x, y = _a.y, z = _a.z, residueIndex = ctx.structure.data.atoms.residueIndex, atomStart = ctx.structure.data.residues.atomStartIndex, atomEnd = ctx.structure.data.residues.atomEndIndex;
                            for (var _i = 0, _c = src.fragments; _i < _c.length; _i++) {
                                var f = _c[_i];
                                var residues_1 = Core.Utils.FastSet.create();
                                for (var _d = 0, _e = f.atomIndices; _d < _e.length; _d++) {
                                    var i = _e[_d];
                                    residues_1.add(residueIndex[i]);
                                    var _f = nearest(x[i], y[i], z[i], radius), elements = _f.elements, count = _f.count;
                                    for (var j = 0; j < count; j++) {
                                        residues_1.add(residueIndex[elements[j]]);
                                    }
                                }
                                var atomCount = { count: 0, start: atomStart, end: atomEnd };
                                residues_1.forEach(function (r, ctx) { ctx.count += ctx.end[r] - ctx.start[r]; }, atomCount);
                                var indices = new Int32Array(atomCount.count), atomIndices = { indices: indices, offset: 0, start: atomStart, end: atomEnd };
                                residues_1.forEach(function (r, ctx) {
                                    for (var i = ctx.start[r], _l = ctx.end[r]; i < _l; i++) {
                                        ctx.indices[ctx.offset++] = i;
                                    }
                                }, atomIndices);
                                Array.prototype.sort.call(indices, function (a, b) { return a - b; });
                                ret.add(Query.Fragment.ofArray(ctx, indices[0], indices));
                            }
                            return ret.getSeq();
                        };
                    }
                    Compiler.compileAmbientResidues = compileAmbientResidues;
                    function compileWholeResidues(where) {
                        var _where = Builder.toQuery(where);
                        return function (ctx) {
                            var src = _where(ctx), ret = new Query.HashFragmentSeqBuilder(ctx), residueIndex = ctx.structure.data.atoms.residueIndex, atomStart = ctx.structure.data.residues.atomStartIndex, atomEnd = ctx.structure.data.residues.atomEndIndex;
                            for (var _i = 0, _a = src.fragments; _i < _a.length; _i++) {
                                var f = _a[_i];
                                var residues_2 = Core.Utils.FastSet.create();
                                for (var _c = 0, _d = f.atomIndices; _c < _d.length; _c++) {
                                    var i = _d[_c];
                                    residues_2.add(residueIndex[i]);
                                }
                                var atomCount = { count: 0, start: atomStart, end: atomEnd };
                                residues_2.forEach(function (r, ctx) { ctx.count += ctx.end[r] - ctx.start[r]; }, atomCount);
                                var indices = new Int32Array(atomCount.count), atomIndices = { indices: indices, offset: 0, start: atomStart, end: atomEnd };
                                residues_2.forEach(function (r, ctx) {
                                    for (var i = ctx.start[r], _l = ctx.end[r]; i < _l; i++) {
                                        ctx.indices[ctx.offset++] = i;
                                    }
                                }, atomIndices);
                                Array.prototype.sort.call(indices, function (a, b) { return a - b; });
                                ret.add(Query.Fragment.ofArray(ctx, indices[0], indices));
                            }
                            return ret.getSeq();
                        };
                    }
                    Compiler.compileWholeResidues = compileWholeResidues;
                    function compileFlatten(what, selector) {
                        var _what = Builder.toQuery(what);
                        return function (ctx) {
                            var fs = _what(ctx);
                            var ret = new Query.HashFragmentSeqBuilder(ctx);
                            for (var _i = 0, _a = fs.fragments; _i < _a.length; _i++) {
                                var f = _a[_i];
                                var xs = selector(f);
                                for (var _c = 0, _d = xs.fragments; _c < _d.length; _c++) {
                                    var x = _d[_c];
                                    ret.add(x);
                                }
                            }
                            return ret.getSeq();
                        };
                    }
                    Compiler.compileFlatten = compileFlatten;
                    function compileExcept(what, toRemove) {
                        var _what = Builder.toQuery(what);
                        var _toRemove = Builder.toQuery(toRemove);
                        return function (ctx) {
                            var fs = _what(ctx);
                            var mask = Core.Utils.Mask.ofFragments(_toRemove(ctx));
                            var ret = new Query.HashFragmentSeqBuilder(ctx);
                            for (var _i = 0, _a = fs.fragments; _i < _a.length; _i++) {
                                var f = _a[_i];
                                var size = 0;
                                for (var _c = 0, _d = f.atomIndices; _c < _d.length; _c++) {
                                    var i = _d[_c];
                                    if (!mask.has(i))
                                        size++;
                                }
                                if (!size)
                                    continue;
                                var indices = new Int32Array(size);
                                var offset = 0;
                                for (var _e = 0, _f = f.atomIndices; _e < _f.length; _e++) {
                                    var i = _f[_e];
                                    if (!mask.has(i))
                                        indices[offset++] = i;
                                }
                                ret.add(Query.Fragment.ofArray(ctx, indices[0], indices));
                            }
                            return ret.getSeq();
                        };
                    }
                    Compiler.compileExcept = compileExcept;
                })(Compiler = Query.Compiler || (Query.Compiler = {}));
            })(Query = Structure.Query || (Structure.Query = {}));
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Core;
    (function (Core) {
        var Structure;
        (function (Structure) {
            var Query;
            (function (Query) {
                var Algebraic;
                (function (Algebraic) {
                    /**
                     * Predicates
                     */
                    function unaryP(f) { return function (a) { return function (ctx, i) { return f(a(ctx, i)); }; }; }
                    function binaryP(f) { return function (a, b) { return function (ctx, i) { return f(a(ctx, i), b(ctx, i)); }; }; }
                    Algebraic.not = unaryP(function (a) { return !a; });
                    Algebraic.and = binaryP(function (a, b) { return a && b; });
                    Algebraic.or = binaryP(function (a, b) { return a || b; });
                    var backboneAtoms = Core.Utils.FastSet.ofArray(["N", "CA", "C", "O", "P", "OP1", "OP2", "O3'", "O5'", "C3'", "C5'", "C4"]);
                    Algebraic.backbone = function (ctx, i) { return Algebraic.entityType(ctx, i) === 'polymer' && backboneAtoms.has(Algebraic.atomName(ctx, i)); };
                    Algebraic.sidechain = function (ctx, i) { return Algebraic.entityType(ctx, i) === 'polymer' && !backboneAtoms.has(Algebraic.atomName(ctx, i)); };
                    /**
                     * Relations
                     */
                    function binaryR(f) { return function (a, b) { return function (ctx, i) { return f(a(ctx, i), b(ctx, i)); }; }; }
                    Algebraic.equal = binaryR(function (a, b) { return a === b; });
                    Algebraic.notEqual = binaryR(function (a, b) { return a !== b; });
                    Algebraic.greater = binaryR(function (a, b) { return a > b; });
                    Algebraic.lesser = binaryR(function (a, b) { return a < b; });
                    Algebraic.greaterEqual = binaryR(function (a, b) { return a >= b; });
                    Algebraic.lesserEqual = binaryR(function (a, b) { return a <= b; });
                    function inRange(s, a, b) { return function (ctx, i) { var v = s(ctx, i); return v >= a && v <= b; }; }
                    Algebraic.inRange = inRange;
                    /**
                     * Selectors
                     */
                    function value(v) { return function () { return v; }; }
                    Algebraic.value = value;
                    function atomProp(index, table, value) { return function (ctx, i) { var s = ctx.structure; return value(table(s))[index(s.data.atoms)[i]]; }; }
                    Algebraic.residueSeqNumber = atomProp(function (m) { return m.residueIndex; }, function (m) { return m.data.residues; }, function (t) { return t.seqNumber; });
                    Algebraic.residueName = atomProp(function (m) { return m.residueIndex; }, function (m) { return m.data.residues; }, function (t) { return t.name; });
                    Algebraic.elementSymbol = atomProp(function (m) { return m.indices; }, function (m) { return m.data.atoms; }, function (t) { return t.elementSymbol; });
                    Algebraic.atomName = atomProp(function (m) { return m.indices; }, function (m) { return m.data.atoms; }, function (t) { return t.name; });
                    Algebraic.entityType = atomProp(function (m) { return m.entityIndex; }, function (m) { return m.data.entities; }, function (t) { return t.type; });
                    /**
                     * Query
                     */
                    function query(p) {
                        return Query.Builder.build(function () { return function (ctx) {
                            var result = [];
                            for (var i = 0, _b = ctx.structure.data.atoms.count; i < _b; i++) {
                                if (ctx.hasAtom(i) && p(ctx, i))
                                    result[result.length] = i;
                            }
                            if (!result.length)
                                return Query.FragmentSeq.empty(ctx);
                            return new Query.FragmentSeq(ctx, [Query.Fragment.ofArray(ctx, result[0], new Int32Array(result))]);
                        }; });
                    }
                    Algebraic.query = query;
                })(Algebraic = Query.Algebraic || (Query.Algebraic = {}));
            })(Query = Structure.Query || (Structure.Query = {}));
        })(Structure = Core.Structure || (Core.Structure = {}));
    })(Core = LiteMol.Core || (LiteMol.Core = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        Visualization.VERSION = { number: "1.7.8", date: "Oct 26 2018" };
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        Visualization.THREE = LiteMolTHREE;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Utils;
        (function (Utils) {
            "use strict";
            var Palette = /** @class */ (function () {
                function Palette() {
                }
                Palette.getRandomColor = function (amountOfGrey) {
                    if (amountOfGrey === void 0) { amountOfGrey = 0.0; }
                    var counter = 0;
                    while (true) {
                        counter++;
                        var c = Palette.randomMix({ r: 166 / 255, g: 0, b: 100 / 255 }, { r: 1, g: 1, b: 0 }, { r: 0, g: 100 / 255, b: 1 }, amountOfGrey);
                        var d = Math.abs(Palette.previous.r - c.r) + Math.abs(Palette.previous.g - c.g) + Math.abs(Palette.previous.b - c.b);
                        if (d > 100 || counter === 10) {
                            Palette.previous = c;
                            return c;
                        }
                    }
                };
                Palette.randomMix = function (color1, color2, color3, greyControl) {
                    var randomIndex = Math.floor(Math.random() * 3) | 0;
                    var mixRatio1 = (randomIndex === 0) ? Math.random() * greyControl : Math.random();
                    var mixRatio2 = (randomIndex === 1) ? Math.random() * greyControl : Math.random();
                    var mixRatio3 = (randomIndex === 2) ? Math.random() * greyControl : Math.random();
                    var sum = mixRatio1 + mixRatio2 + mixRatio3;
                    mixRatio1 /= sum;
                    mixRatio2 /= sum;
                    mixRatio3 /= sum;
                    return {
                        r: (mixRatio1 * color1.r + mixRatio2 * color2.r + mixRatio3 * color3.r),
                        g: (mixRatio1 * color1.g + mixRatio2 * color2.g + mixRatio3 * color3.g),
                        b: (mixRatio1 * color1.b + mixRatio2 * color2.b + mixRatio3 * color3.b)
                    };
                };
                /**
                 *
                 * @example
                 *   let min = Palette.getRandomColor(0.3);
                 *   let max = Palette.getRandomColor(0.3);
                 *   let color = Palette.interpolate(0.1, min, 0.6, max, 0.354);
                 */
                Palette.interpolate = function (min, minColor, max, maxColor, value, target) {
                    var ret = target !== void 0 ? target : { r: 0.1, g: 0.1, b: 0.1 };
                    var t = (value - min) / (max - min);
                    ret.r = minColor.r + (maxColor.r - minColor.r) * t;
                    ret.g = minColor.g + (maxColor.g - minColor.g) * t;
                    ret.b = minColor.b + (maxColor.b - minColor.b) * t;
                    return ret;
                };
                Palette.previous = Palette.randomMix({ r: 0.75, g: 0, b: 0.25 }, { r: 1, g: 0.5, b: 0 }, { r: 0, g: 0.35, b: 1 }, 0.5);
                return Palette;
            }());
            Utils.Palette = Palette;
        })(Utils = Visualization.Utils || (Visualization.Utils = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        function checkWebGL() {
            var canvas = document.createElement('canvas');
            try {
                var ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
                return !!ctx;
            }
            catch (e) {
                console.log(e);
                return false;
            }
        }
        Visualization.checkWebGL = checkWebGL;
        var GeometryHelper = /** @class */ (function () {
            function GeometryHelper() {
            }
            GeometryHelper.setPickBase = function (objectId, objectIdWidth, elementId, color) {
                var width = 24, value = objectId << (width - objectIdWidth) | elementId, r = (value >> 16) & 0xFF, g = (value >> 8) & 0xFF, b = value & 0xFF;
                color.r = r / 255.0;
                color.g = g / 255.0;
                color.b = b / 255.0;
            };
            GeometryHelper.setPickColor = function (objectId, objectIdWidth, elementId, buffer, offset) {
                var width = 24, value = objectId << (width - objectIdWidth) | elementId, r = (value >> 16) & 0xFF, g = (value >> 8) & 0xFF, b = value & 0xFF;
                buffer[offset] = r / 255.0;
                buffer[offset + 1] = g / 255.0;
                buffer[offset + 2] = b / 255.0;
            };
            GeometryHelper.toSurface = function (source) {
                var bufferSize = source.vertices.length * 3, vertexBuffer = new Float32Array(bufferSize), normalBuffer = new Float32Array(bufferSize), indexBuffer = new Uint32Array(source.faces.length * 3), normals = Array(source.vertices.length);
                for (var i = 0; i < source.faces.length; i++) {
                    var f = source.faces[i];
                    normals[f.a] = f.vertexNormals[0];
                    normals[f.b] = f.vertexNormals[1];
                    normals[f.c] = f.vertexNormals[2];
                    indexBuffer[3 * i] = f.a;
                    indexBuffer[3 * i + 1] = f.b;
                    indexBuffer[3 * i + 2] = f.c;
                }
                for (var i = 0; i < source.vertices.length; i++) {
                    var v = source.vertices[i];
                    vertexBuffer[3 * i] = v.x;
                    vertexBuffer[3 * i + 1] = v.y;
                    vertexBuffer[3 * i + 2] = v.z;
                    var n = normals[i];
                    normalBuffer[3 * i] = n.x;
                    normalBuffer[3 * i + 1] = n.y;
                    normalBuffer[3 * i + 2] = n.z;
                }
                return {
                    vertices: vertexBuffer,
                    vertexCount: source.vertices.length,
                    triangleIndices: indexBuffer,
                    triangleCount: source.faces.length,
                    normals: normalBuffer
                };
            };
            GeometryHelper.toRawGeometry = function (source) {
                var _a = GeometryHelper.toSurface(source), vertices = _a.vertices, vertexCount = _a.vertexCount, indices = _a.triangleIndices, indexCount = _a.triangleCount, normals = _a.normals;
                return {
                    vertices: vertices,
                    vertexCount: vertexCount,
                    indices: indices,
                    indexCount: indexCount,
                    normals: normals,
                    elementSize: 3
                };
            };
            GeometryHelper.getIndexedBufferGeometry = function (source) {
                var bufferSize = source.vertices.length * 3, vertexBuffer = new Float32Array(bufferSize), normalBuffer = new Float32Array(bufferSize), indexBuffer = new Uint32Array(source.faces.length * 3), normals = Array(source.vertices.length);
                for (var i = 0; i < source.faces.length; i++) {
                    var f = source.faces[i];
                    normals[f.a] = f.vertexNormals[0];
                    normals[f.b] = f.vertexNormals[1];
                    normals[f.c] = f.vertexNormals[2];
                    indexBuffer[3 * i] = f.a;
                    indexBuffer[3 * i + 1] = f.b;
                    indexBuffer[3 * i + 2] = f.c;
                }
                for (var i = 0; i < source.vertices.length; i++) {
                    var v = source.vertices[i];
                    vertexBuffer[3 * i] = v.x;
                    vertexBuffer[3 * i + 1] = v.y;
                    vertexBuffer[3 * i + 2] = v.z;
                    var n = normals[i];
                    normalBuffer[3 * i] = n.x;
                    normalBuffer[3 * i + 1] = n.y;
                    normalBuffer[3 * i + 2] = n.z;
                }
                var geom = new Visualization.THREE.BufferGeometry();
                geom.addAttribute('position', new Visualization.THREE.BufferAttribute(vertexBuffer, 3));
                geom.addAttribute('normal', new Visualization.THREE.BufferAttribute(normalBuffer, 3));
                geom.addAttribute('index', new Visualization.THREE.BufferAttribute(indexBuffer, 1));
                return geom;
            };
            return GeometryHelper;
        }());
        Visualization.GeometryHelper = GeometryHelper;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Color;
        (function (Color) {
            function copy(from, to) {
                to.r = from.r;
                to.g = from.g;
                to.b = from.b;
            }
            Color.copy = copy;
            function clone(_a) {
                var r = _a.r, g = _a.g, b = _a.b;
                return { r: r, g: g, b: b };
            }
            Color.clone = clone;
            function toVector(color) {
                return new Visualization.THREE.Vector3(color.r, color.g, color.b);
            }
            Color.toVector = toVector;
            function fromVector(v) {
                return { r: v.x, g: v.y, b: v.z };
            }
            Color.fromVector = fromVector;
            function fromRgb(r, g, b) {
                return { r: r / 255, g: g / 255, b: b / 255 };
            }
            Color.fromRgb = fromRgb;
            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;
            }
            function fromHsl(h, s, l) {
                //http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion            
                var r, g, b;
                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, g: g, b: b };
            }
            Color.fromHsl = fromHsl;
            function fromHsv(h, s, v) {
                //http://schinckel.net/2012/01/10/hsv-to-rgb-in-javascript/          
                var rgb, i, data = [];
                if (s === 0) {
                    rgb = [v, v, v];
                }
                else {
                    h = h / 60;
                    i = Math.floor(h);
                    data = [v * (1 - s), v * (1 - s * (h - i)), v * (1 - s * (1 - (h - i)))];
                    switch (i) {
                        case 0:
                            rgb = [v, data[2], data[0]];
                            break;
                        case 1:
                            rgb = [data[1], v, data[0]];
                            break;
                        case 2:
                            rgb = [data[0], v, data[2]];
                            break;
                        case 3:
                            rgb = [data[0], data[1], v];
                            break;
                        case 4:
                            rgb = [data[2], data[0], v];
                            break;
                        default:
                            rgb = [v, data[0], data[1]];
                            break;
                    }
                }
                return { r: rgb[0], g: rgb[1], b: rgb[2] };
            }
            Color.fromHsv = fromHsv;
            function random() {
                return Visualization.Utils.Palette.getRandomColor();
            }
            Color.random = random;
            // #rrggbb
            function fromHex(v) {
                return { r: ((v >> 16) & 0xFF) / 255.0, g: ((v >> 8) & 0xFF) / 255.0, b: (v & 0xFF) / 255.0 };
            }
            Color.fromHex = fromHex;
            /**
             * Parse color in formats #rgb and #rrggbb
             */
            function fromHexString(s) {
                if (s[0] !== '#')
                    return fromHex(0);
                if (s.length === 4) { // #rgb
                    return fromHexString("#" + s[1] + s[1] + s[2] + s[2] + s[3] + s[3]);
                }
                else if (s.length === 7) { // #rrggbb
                    return fromHex(parseInt(s.substr(1), 16));
                }
                return fromHex(0);
            }
            Color.fromHexString = fromHexString;
            function interpolate(a, b, t, target) {
                target.r = a.r + (b.r - a.r) * t;
                target.g = a.g + (b.g - a.g) * t;
                target.b = a.b + (b.b - a.b) * t;
            }
            Color.interpolate = interpolate;
            function isColor(c) {
                return c.r !== void 0 && c.g !== void 0 && c.b !== void 0;
            }
            Color.isColor = isColor;
        })(Color = Visualization.Color || (Visualization.Color = {}));
        var Theme;
        (function (Theme) {
            var Default;
            (function (Default) {
                Default.HighlightColor = { r: 1.0, g: 1.0, b: 0 };
                Default.SelectionColor = { r: 171 / 255, g: 71 / 255, b: 183 / 255 }; //{ r: 1.0, g: 0.0, b: 0.0 };
                Default.UniformColor = { r: 68 / 255, g: 130 / 255, b: 255 };
                Default.Transparency = { alpha: 1.0, writeDepth: false };
            })(Default = Theme.Default || (Theme.Default = {}));
            function isTransparent(theme) {
                var opacity = +theme.transparency.alpha;
                if (isNaN(opacity))
                    opacity = 1.0;
                return opacity <= 0.999;
            }
            Theme.isTransparent = isTransparent;
            function getColor(theme, name, fallback) {
                var c = theme.colors.get(name);
                if (!c)
                    return fallback;
                return c;
            }
            Theme.getColor = getColor;
            function createUniform(props) {
                if (props === void 0) { props = {}; }
                var colors = props.colors, _a = props.variables, variables = _a === void 0 ? LiteMol.Core.Utils.FastMap.create() : _a, _b = props.transparency, transparency = _b === void 0 ? Default.Transparency : _b, _c = props.interactive, interactive = _c === void 0 ? true : _c, _d = props.disableFog, disableFog = _d === void 0 ? false : _d, _e = props.isSticky, isSticky = _e === void 0 ? false : _e;
                var finalColors = LiteMol.Core.Utils.FastMap.create();
                if (colors) {
                    colors.forEach(function (c, n) { return finalColors.set(n, c); });
                }
                var uniform = finalColors.get('Uniform');
                if (!uniform) {
                    finalColors.set('Uniform', Default.UniformColor);
                    uniform = Default.UniformColor;
                }
                return {
                    colors: finalColors,
                    variables: variables,
                    transparency: transparency,
                    interactive: interactive,
                    disableFog: disableFog,
                    isSticky: isSticky,
                    setElementColor: function (index, target) {
                        Color.copy(uniform, target);
                    }
                };
            }
            Theme.createUniform = createUniform;
            function createMapping(mapping, props) {
                if (props === void 0) { props = {}; }
                var _a = props.colors, colors = _a === void 0 ? LiteMol.Core.Utils.FastMap.create() : _a, _b = props.variables, variables = _b === void 0 ? LiteMol.Core.Utils.FastMap.create() : _b, _c = props.transparency, transparency = _c === void 0 ? Default.Transparency : _c, _d = props.interactive, interactive = _d === void 0 ? true : _d, _e = props.disableFog, disableFog = _e === void 0 ? false : _e, _f = props.isSticky, isSticky = _f === void 0 ? false : _f;
                return {
                    colors: colors,
                    variables: variables,
                    transparency: transparency ? transparency : Default.Transparency,
                    interactive: interactive,
                    disableFog: disableFog,
                    isSticky: isSticky,
                    setElementColor: function (index, target) {
                        mapping.setColor(mapping.getProperty(index), target);
                    }
                };
            }
            Theme.createMapping = createMapping;
            function createColorMapMapping(getProperty, map, fallbackColor) {
                var mapper = new ColorMapMapper(map, fallbackColor);
                return {
                    getProperty: getProperty,
                    setColor: function (i, c) { return mapper.setColor(i, c); }
                };
            }
            Theme.createColorMapMapping = createColorMapMapping;
            function createPalleteMapping(getProperty, pallete) {
                var mapper = new PaletteMapper(pallete);
                return {
                    getProperty: getProperty,
                    setColor: function (i, c) { return mapper.setColor(i, c); }
                };
            }
            Theme.createPalleteMapping = createPalleteMapping;
            function createPalleteIndexMapping(getProperty, pallete) {
                var mapper = new PaletteIndexMapper(pallete);
                return {
                    getProperty: getProperty,
                    setColor: function (i, c) { return mapper.setColor(i, c); }
                };
            }
            Theme.createPalleteIndexMapping = createPalleteIndexMapping;
            var PaletteIndexMapper = /** @class */ (function () {
                function PaletteIndexMapper(pallete) {
                    this.pallete = pallete;
                }
                PaletteIndexMapper.prototype.setColor = function (i, target) {
                    var color = this.pallete[i];
                    Color.copy(color, target);
                };
                return PaletteIndexMapper;
            }());
            var PaletteMapper = /** @class */ (function () {
                function PaletteMapper(pallete) {
                    this.pallete = pallete;
                    this.colorIndex = 0;
                    this.colorMap = LiteMol.Core.Utils.FastMap.create();
                }
                PaletteMapper.prototype.setColor = function (p, target) {
                    var color = this.colorMap.get(p);
                    if (!color) {
                        this.colorIndex = ((this.colorIndex + 1) % this.pallete.length) | 0;
                        color = this.pallete[this.colorIndex];
                        this.colorMap.set(p, color);
                    }
                    Color.copy(color, target);
                };
                return PaletteMapper;
            }());
            var ColorMapMapper = /** @class */ (function () {
                function ColorMapMapper(map, fallbackColor) {
                    this.map = map;
                    this.fallbackColor = fallbackColor;
                }
                ColorMapMapper.prototype.setColor = function (p, target) {
                    var color = this.map.get(p);
                    if (!color) {
                        color = this.fallbackColor;
                    }
                    Color.copy(color, target);
                };
                return ColorMapMapper;
            }());
        })(Theme = Visualization.Theme || (Visualization.Theme = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var MaterialsHelper = /** @class */ (function () {
            function MaterialsHelper() {
            }
            MaterialsHelper.getPickMaterial = function () {
                return new Visualization.THREE.ShaderMaterial({
                    attributes: { pColor: { type: 'v4', value: [] } },
                    vertexShader: MaterialsHelper.pickVertexShader,
                    fragmentShader: MaterialsHelper.pickFragmentShader,
                    blending: Visualization.THREE.NoBlending,
                    shading: Visualization.THREE.FlatShading,
                    side: Visualization.THREE.DoubleSide
                });
            };
            MaterialsHelper.getPickExcludeMaterial = function () {
                return new Visualization.THREE.MeshBasicMaterial({ color: Visualization.THREE.ColorKeywords.white, side: Visualization.THREE.DoubleSide });
            };
            MaterialsHelper.compareVectorAndColor = function (v, c) {
                return v.x === c.r && v.y === c.g && v.z === c.b;
            };
            MaterialsHelper.updateMaterial = function (material, theme, object) {
                var changed = false;
                if (MaterialsHelper.updateTransparencyAndFog(material, theme, object))
                    changed = true;
                if (material instanceof Visualization.THREE.ShaderMaterial && MaterialsHelper.updateHighlightColor(material, theme))
                    changed = true;
                if (changed)
                    material.needsUpdate = true;
            };
            MaterialsHelper.updateHighlightColor = function (material, theme) {
                var changed = false;
                var color = material.uniforms.selectionColor.value;
                var selectionColor = Visualization.Theme.getColor(theme, 'Selection', Visualization.Theme.Default.SelectionColor);
                if (!MaterialsHelper.compareVectorAndColor(color, selectionColor)) {
                    material.uniforms.selectionColor.value = Visualization.Color.toVector(selectionColor);
                    changed = true;
                }
                color = material.uniforms.highlightColor.value;
                var highlightColor = Visualization.Theme.getColor(theme, 'Highlight', Visualization.Theme.Default.HighlightColor);
                if (!MaterialsHelper.compareVectorAndColor(color, highlightColor)) {
                    material.uniforms.highlightColor.value = Visualization.Color.toVector(highlightColor);
                    changed = true;
                }
                return changed;
            };
            MaterialsHelper.updateTransparencyAndFog = function (material, theme, object) {
                var transparency = theme.transparency;
                var opacity = +transparency.alpha;
                if (isNaN(opacity))
                    opacity = 1.0;
                var isTransparent = opacity <= 0.999;
                var writeDepth = !!transparency.writeDepth;
                if (!isTransparent) {
                    opacity = 1.0;
                    writeDepth = true;
                }
                if (object)
                    object.renderOrder = isTransparent ? 1 : 0;
                var changed = false;
                if (material instanceof Visualization.THREE.MeshPhongMaterial || material instanceof Visualization.THREE.MeshBasicMaterial || material instanceof Visualization.THREE.ShaderMaterial) {
                    if (material.transparent !== isTransparent) {
                        material.transparent = isTransparent;
                        changed = true;
                    }
                    if (material.depthWrite !== writeDepth) {
                        material.depthWrite = writeDepth;
                        changed = true;
                    }
                    if (material.opacity !== opacity) {
                        material.opacity = opacity;
                        changed = true;
                    }
                    if (material.fog !== !theme.disableFog) {
                        material.fog = !theme.disableFog;
                        changed = true;
                    }
                    if (material instanceof Visualization.THREE.ShaderMaterial) {
                        if (material.uniforms.opacity) {
                            material.uniforms.opacity.value = opacity;
                        }
                    }
                }
                return changed;
            };
            MaterialsHelper.getMeshMaterial = function (shading, isWireframe) {
                if (shading === void 0) { shading = Visualization.THREE.SmoothShading; }
                if (isWireframe === void 0) { isWireframe = false; }
                var shader = MaterialsHelper.shader;
                var ret = new Visualization.THREE.ShaderMaterial({
                    uniforms: Visualization.THREE.UniformsUtils.clone(shader.uniforms),
                    attributes: { "vState": { type: 'f', value: [] } },
                    lights: true,
                    fog: true,
                    vertexShader: shader.vertexShader,
                    fragmentShader: shader.fragmentShader,
                    shading: shading,
                    side: Visualization.THREE.DoubleSide,
                    vertexColors: Visualization.THREE.VertexColors,
                    blending: Visualization.THREE.NormalBlending,
                    wireframe: isWireframe,
                    linewidth: 1
                });
                return ret;
            };
            MaterialsHelper.getPhongVertexColorMaterial = function () {
                return new Visualization.THREE.MeshPhongMaterial({ specular: 0xAAAAAA, /*ambient: 0xffffff, */ shininess: 2, shading: Visualization.THREE.SmoothShading, vertexColors: Visualization.THREE.VertexColors, side: Visualization.THREE.DoubleSide, metal: true });
            };
            MaterialsHelper.getDefaultHighlightMaterial = function () {
                return new Visualization.THREE.MeshPhongMaterial({ color: 0xFFFFFF, specular: 0xAAAAAA, /* ambient: 0xffffff,*/ shininess: 2, shading: Visualization.THREE.SmoothShading, side: Visualization.THREE.DoubleSide, metal: true });
            };
            MaterialsHelper.applyColorToBuffer = function (bufferAttribute, color) {
                var buffer = bufferAttribute.array;
                for (var i = 0, __i = buffer.length; i < __i; i += 3) {
                    buffer[i] = color.r;
                    buffer[i + 1] = color.g;
                    buffer[i + 2] = color.b;
                }
                bufferAttribute.needsUpdate = true;
            };
            MaterialsHelper.applyColorToMap = function (map, bufferAttribute, getter) {
                var buffer = bufferAttribute.array, color = { r: 0.45, g: 0.45, b: 0.45 }, vertexRanges = map.vertexRanges;
                for (var _i = 0, _a = map.elementIndices; _i < _a.length; _i++) {
                    var elementIndex = _a[_i];
                    var elementOffset = map.elementMap.get(elementIndex);
                    var rangeStart = map.elementRanges[2 * elementOffset], rangeEnd = map.elementRanges[2 * elementOffset + 1];
                    if (rangeStart === rangeEnd)
                        continue;
                    getter(elementIndex, color);
                    for (var i = rangeStart; i < rangeEnd; i += 2) {
                        var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                        for (var j = vStart; j < vEnd; j++) {
                            buffer[j * 3] = color.r,
                                buffer[j * 3 + 1] = color.g,
                                buffer[j * 3 + 2] = color.b;
                        }
                    }
                }
                bufferAttribute.needsUpdate = true;
            };
            MaterialsHelper.pickVertexShader = [
                "attribute vec4 pColor;",
                "varying vec4 pC;",
                "void main() {",
                "pC = pColor;",
                "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
                "}"
            ].join('\n');
            MaterialsHelper.pickFragmentShader = [
                "varying vec4 pC;",
                "void main() {",
                "gl_FragColor = pC;",
                "}"
            ].join('\n');
            MaterialsHelper.shader = {
                uniforms: Visualization.THREE.UniformsUtils.merge([
                    Visualization.THREE.UniformsLib["common"],
                    Visualization.THREE.UniformsLib["bump"],
                    Visualization.THREE.UniformsLib["normalmap"],
                    Visualization.THREE.UniformsLib["fog"],
                    Visualization.THREE.UniformsLib["lights"],
                    Visualization.THREE.UniformsLib["shadowmap"],
                    {
                        "emissive": { type: "c", value: new Visualization.THREE.Color(0x000000) },
                        "specular": { type: "c", value: new Visualization.THREE.Color(0x111111) },
                        "shininess": { type: "f", value: 2 },
                        "wrapRGB": { type: "v3", value: new Visualization.THREE.Vector3(1, 1, 1) },
                        "highlightColor": { type: "v3", value: new Visualization.THREE.Vector3(1, 1, 0) },
                        "selectionColor": { type: "v3", value: new Visualization.THREE.Vector3(1, 0, 0) },
                    }
                ]),
                vertexShader: [
                    "#define PHONG",
                    "varying vec3 vViewPosition;",
                    "#ifndef FLAT_SHADED",
                    "	varying vec3 vNormal;",
                    "#endif",
                    Visualization.THREE.ShaderChunk["common"],
                    Visualization.THREE.ShaderChunk["map_pars_vertex"],
                    Visualization.THREE.ShaderChunk["lightmap_pars_vertex"],
                    Visualization.THREE.ShaderChunk["envmap_pars_vertex"],
                    Visualization.THREE.ShaderChunk["lights_phong_pars_vertex"],
                    Visualization.THREE.ShaderChunk["color_pars_vertex"],
                    Visualization.THREE.ShaderChunk["morphtarget_pars_vertex"],
                    Visualization.THREE.ShaderChunk["skinning_pars_vertex"],
                    Visualization.THREE.ShaderChunk["shadowmap_pars_vertex"],
                    Visualization.THREE.ShaderChunk["logdepthbuf_pars_vertex"],
                    "attribute float vState;",
                    "varying float vS;",
                    "void main() {",
                    "   vS = vState;",
                    Visualization.THREE.ShaderChunk["map_vertex"],
                    Visualization.THREE.ShaderChunk["lightmap_vertex"],
                    Visualization.THREE.ShaderChunk["color_vertex"],
                    Visualization.THREE.ShaderChunk["morphnormal_vertex"],
                    Visualization.THREE.ShaderChunk["skinbase_vertex"],
                    Visualization.THREE.ShaderChunk["skinnormal_vertex"],
                    Visualization.THREE.ShaderChunk["defaultnormal_vertex"],
                    "#ifndef FLAT_SHADED",
                    "	vNormal = normalize( transformedNormal );",
                    "#endif",
                    Visualization.THREE.ShaderChunk["morphtarget_vertex"],
                    Visualization.THREE.ShaderChunk["skinning_vertex"],
                    Visualization.THREE.ShaderChunk["default_vertex"],
                    Visualization.THREE.ShaderChunk["logdepthbuf_vertex"],
                    "	vViewPosition = -mvPosition.xyz;",
                    Visualization.THREE.ShaderChunk["worldpos_vertex"],
                    Visualization.THREE.ShaderChunk["envmap_vertex"],
                    Visualization.THREE.ShaderChunk["lights_phong_vertex"],
                    Visualization.THREE.ShaderChunk["shadowmap_vertex"],
                    "}"
                ].join("\n"),
                fragmentShader: [
                    "#define PHONG",
                    "uniform vec3 diffuse;",
                    "uniform vec3 emissive;",
                    "uniform vec3 specular;",
                    "uniform float shininess;",
                    "uniform float opacity;",
                    "uniform vec3 highlightColor;",
                    "uniform vec3 selectionColor;",
                    Visualization.THREE.ShaderChunk["common"],
                    Visualization.THREE.ShaderChunk["color_pars_fragment"],
                    Visualization.THREE.ShaderChunk["map_pars_fragment"],
                    Visualization.THREE.ShaderChunk["alphamap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["lightmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["envmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["fog_pars_fragment"],
                    Visualization.THREE.ShaderChunk["lights_phong_pars_fragment"],
                    Visualization.THREE.ShaderChunk["shadowmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["bumpmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["normalmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["specularmap_pars_fragment"],
                    Visualization.THREE.ShaderChunk["logdepthbuf_pars_fragment"],
                    "varying float vS;",
                    "void main() {",
                    "	vec3 outgoingLight = vec3( 0.0 );",
                    "	vec4 diffuseColor;",
                    "   if (vS < 0.33) { diffuseColor = vec4( vColor, opacity ); }",
                    "   else if (vS - floor(vS + 0.1) > 0.33) { diffuseColor = vec4(highlightColor, opacity); }",
                    "	else { diffuseColor = vec4(selectionColor, opacity); }",
                    Visualization.THREE.ShaderChunk["logdepthbuf_fragment"],
                    Visualization.THREE.ShaderChunk["map_fragment"],
                    //THREE.ShaderChunk["color_fragment"], 
                    Visualization.THREE.ShaderChunk["alphamap_fragment"],
                    Visualization.THREE.ShaderChunk["alphatest_fragment"],
                    Visualization.THREE.ShaderChunk["specularmap_fragment"],
                    Visualization.THREE.ShaderChunk["lights_phong_fragment"],
                    Visualization.THREE.ShaderChunk["lightmap_fragment"],
                    Visualization.THREE.ShaderChunk["envmap_fragment"],
                    Visualization.THREE.ShaderChunk["shadowmap_fragment"],
                    Visualization.THREE.ShaderChunk["linear_to_gamma_fragment"],
                    Visualization.THREE.ShaderChunk["fog_fragment"],
                    "#ifdef USE_FOG",
                    "   if (diffuseColor.a > 0.99) { gl_FragColor = vec4( outgoingLight, diffuseColor.a ); }",
                    "   else { gl_FragColor = vec4( outgoingLight, (1.0 - fogFactor) * diffuseColor.a ); }",
                    "#else",
                    "	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
                    "#endif",
                    "}"
                ].join("\n")
            };
            return MaterialsHelper;
        }());
        Visualization.MaterialsHelper = MaterialsHelper;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var GeometryBase = /** @class */ (function () {
            function GeometryBase() {
            }
            return GeometryBase;
        }());
        Visualization.GeometryBase = GeometryBase;
        var Model = /** @class */ (function () {
            function Model() {
                this.id = -1; // assigned by "manager"
                // base
                this.entity = void 0;
                // bounds
                this.centroid = new Visualization.THREE.Vector3();
                this.radius = 0;
                // object
                this.object = void 0;
                this.theme = void 0;
                this.disposeList = [];
                // picking
                this.pickObject = void 0;
                this.pickBufferAttributes = [];
                // state
                this.dirty = false;
                this.props = {};
                this.tag = void 0;
            }
            Model.prototype.updateVisibility = function (visible) {
                this.dirty = true;
                this.object.visible = visible;
                if (this.pickObject) {
                    this.pickObject.visible = this.getPickObjectVisibility(visible);
                }
            };
            Model.prototype.getVisibility = function () {
                return this.object.visible;
            };
            Model.prototype.applyTheme = function (theme) {
                this.dirty = true;
                this.theme = theme;
                if (!theme.interactive) {
                    if (this.pickObject)
                        this.pickObject.visible = false;
                }
                else {
                    if (this.pickObject)
                        this.pickObject.visible = this.object.visible;
                }
                this.applyThemeInternal(theme);
            };
            Model.prototype.updateId = function (id, idWidth) {
                this.id = id;
                for (var _i = 0, _a = this.pickBufferAttributes; _i < _a.length; _i++) {
                    var attr = _a[_i];
                    var buffer = attr.array;
                    if (idWidth <= 8) {
                        for (var i = 0, _b = buffer.length; i < _b; i += 4) {
                            Visualization.Selection.Picking.applySceneIdFast(this.id, i, buffer);
                        }
                    }
                    else {
                        for (var i = 0, _b = buffer.length; i < _b; i += 4) {
                            Visualization.Selection.Picking.applySceneIdSlow(idWidth - 8, this.id, i, buffer);
                        }
                    }
                    attr.needsUpdate = true;
                }
            };
            Model.prototype.dispose = function () {
                for (var _i = 0, _a = this.disposeList; _i < _a.length; _i++) {
                    var d = _a[_i];
                    if (d)
                        d.dispose();
                }
                this.disposeList = [];
            };
            Model.prototype.highlight = function (isOn) {
                var changed = this.highlightInternal(isOn);
                this.dirty = this.dirty || changed;
                return changed;
            };
            Model.prototype.applySelection = function (indices, action) {
                var changed = this.applySelectionInternal(indices, action);
                this.dirty = this.dirty || changed;
                return changed;
            };
            Model.prototype.getBoundingSphereOfSelection = function (indices) {
                return undefined;
            };
            Model.prototype.getPickObjectVisibility = function (visible) {
                return visible && this.theme.interactive;
            };
            return Model;
        }());
        Visualization.Model = Model;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var ModelStore = /** @class */ (function () {
            function ModelStore(scene) {
                this.scene = scene;
                this.availableIds = [];
                this.list = [];
                this.map = LiteMol.Core.Utils.FastMap.create();
                this.maxId = 1;
                this._idWidth = 8;
            }
            Object.defineProperty(ModelStore.prototype, "idWidth", {
                get: function () {
                    return this._idWidth;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(ModelStore.prototype, "all", {
                get: function () {
                    return this.list;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(ModelStore.prototype, "count", {
                get: function () {
                    return this.map.size;
                },
                enumerable: true,
                configurable: true
            });
            ModelStore.prototype.getBySceneId = function (id) {
                return this.map.get(id);
            };
            ModelStore.prototype.add = function (model, resetCamera) {
                if (resetCamera === void 0) { resetCamera = true; }
                var id = -1;
                if (this.availableIds.length) {
                    id = this.availableIds.pop();
                }
                else {
                    id = this.maxId++;
                }
                this.map.set(id, model);
                this.list.push(model);
                model.updateId(id, 8);
                if (model.object) {
                    this.scene.scene.add(model.object);
                }
                if (model.pickObject)
                    this.scene.pickScene.add(model.pickObject);
                if (resetCamera) {
                    this.scene.camera.reset();
                }
                else {
                    this.scene.forceRender();
                }
            };
            ModelStore.prototype.dispose = function (model) {
                if (model.object) {
                    this.scene.scene.remove(model.object);
                }
                if (model.pickObject)
                    this.scene.pickScene.remove(model.pickObject);
                model.dispose();
            };
            ModelStore.prototype.removeAndDispose = function (model) {
                if (!this.map.get(model.id))
                    return;
                this.availableIds.push(model.id);
                this.dispose(model);
                this.map.delete(model.id);
                var idx = this.list.indexOf(model);
                this.list[idx] = this.list[this.list.length - 1];
                this.list.pop();
                if (model.id === this.maxId)
                    this.maxId--;
                model.id = -1;
                this.scene.forceRender();
            };
            ModelStore.prototype.clear = function () {
                for (var _i = 0, _a = this.list; _i < _a.length; _i++) {
                    var m = _a[_i];
                    this.dispose(m);
                }
                this.list = [];
                this.maxId = 0;
                this.availableIds = [];
                this.map.clear();
                this.scene.forceRender();
            };
            return ModelStore;
        }());
        Visualization.ModelStore = ModelStore;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var CameraType;
        (function (CameraType) {
            CameraType[CameraType["Perspective"] = 0] = "Perspective";
            CameraType[CameraType["Orthographic"] = 1] = "Orthographic";
        })(CameraType = Visualization.CameraType || (Visualization.CameraType = {}));
        var LA = LiteMol.Core.Geometry.LinearAlgebra;
        var SlabControls = /** @class */ (function () {
            function SlabControls(element) {
                var _this = this;
                this.touchSlabOn = false;
                this.touchStartPosition = { x: 0, y: 0 };
                this.touchPosition = { x: 0, y: 0 };
                this.radius = 0;
                this.slabWheelRate = 1 / 15;
                this._planeDelta = new LiteMol.Core.Rx.Subject();
                this.subs = [];
                this.enableWheel = false;
                this.mouseMoveDelta = 0;
                this.lastMousePosition = void 0;
                this.planeDelta = this._planeDelta;
                var events = {
                    wheel: function (e) { return _this.handleMouseWheel(e); },
                    touchStart: function (e) { return _this.touchstart(e); },
                    touchEnd: function (e) { return _this.touchend(e); },
                    touchMove: function (e) { return _this.touchmove(e); },
                    mouseMove: function (e) { return _this.mousemove(e); },
                    mouseOut: function () { return _this.mouseOut(); }
                };
                element.addEventListener('mousewheel', events.wheel);
                element.addEventListener('DOMMouseScroll', events.wheel); // firefox   
                element.addEventListener('mousemove', events.mouseMove);
                element.addEventListener('mouseout', events.mouseOut);
                element.addEventListener('touchstart', events.touchStart, false);
                element.addEventListener('touchend', events.touchEnd, false);
                element.addEventListener('touchmove', events.touchMove, false);
                this.subs.push(function () { return element.removeEventListener('mousewheel', events.wheel); });
                this.subs.push(function () { return element.removeEventListener('mousemove', events.mouseMove); });
                this.subs.push(function () { return element.removeEventListener('mouseout', events.mouseOut); });
                this.subs.push(function () { return element.removeEventListener('DOMMouseScroll', events.wheel); });
                this.subs.push(function () { return element.removeEventListener('touchstart', events.touchStart, false); });
                this.subs.push(function () { return element.removeEventListener('touchend', events.touchEnd, false); });
                this.subs.push(function () { return element.removeEventListener('touchmove', events.touchMove, false); });
            }
            SlabControls.prototype.updateSize = function (w, h) { /* this.width = w;*/ this.height = h; };
            SlabControls.prototype.updateRadius = function (r) { this.radius = r; };
            SlabControls.prototype.destroy = function () {
                for (var _i = 0, _a = this.subs; _i < _a.length; _i++) {
                    var s = _a[_i];
                    s();
                }
                this.subs = [];
                this._planeDelta.onCompleted();
            };
            SlabControls.prototype.handleMouseWheel = function (event) {
                if (!this.enableWheel)
                    return;
                //if (!this.options.enableFrontClip) return;
                if (event.stopPropagation) {
                    event.stopPropagation();
                }
                if (event.preventDefault) {
                    event.preventDefault();
                }
                var delta = 0;
                if (event.wheelDelta) { // WebKit / Opera / Explorer 9
                    delta = event.wheelDelta;
                }
                else if (event.detail) { // Firefox
                    delta = -event.detail;
                }
                //if (delta < -0.5) delta = -0.5;
                //else if (delta > 0.5) delta = 0.5;
                var sign = delta < 0 ? 1 : -1;
                delta = this.radius * this.slabWheelRate * sign;
                this._planeDelta.onNext(delta);
            };
            SlabControls.prototype.touchstart = function (event) {
                switch (event.touches.length) {
                    case 3: {
                        this.touchStartPosition.x = 0;
                        this.touchStartPosition.y = 0;
                        for (var i = 0; i < 3; i++) {
                            this.touchStartPosition.x += event.touches[i].clientX / 3;
                            this.touchStartPosition.y += event.touches[i].clientY / 3;
                        }
                        this.touchSlabOn = true;
                        break;
                    }
                    default:
                        this.touchSlabOn = false;
                        break;
                }
            };
            SlabControls.prototype.touchend = function (event) {
                this.touchSlabOn = false;
            };
            SlabControls.prototype.touchmove = function (event) {
                if (!this.touchSlabOn)
                    return;
                this.touchPosition.x = 0;
                this.touchPosition.y = 0;
                for (var i = 0; i < 3; i++) {
                    this.touchPosition.x += event.touches[i].clientX / 3;
                    this.touchPosition.y += event.touches[i].clientY / 3;
                }
                var delta = -5 * this.radius * (this.touchPosition.y - this.touchStartPosition.y) / this.height;
                this.touchStartPosition.x = this.touchPosition.x;
                this.touchStartPosition.y = this.touchPosition.y;
                this._planeDelta.onNext(delta);
            };
            SlabControls.prototype.mousemove = function (e) {
                if (!this.lastMousePosition) {
                    this.lastMousePosition = [e.clientX, e.clientY, 0];
                    return;
                }
                var pos = [e.clientX, e.clientY, 0];
                this.mouseMoveDelta += LA.Vector3.distance(pos, this.lastMousePosition);
                this.lastMousePosition = pos;
                if (this.mouseMoveDelta > 15)
                    this.enableWheel = true;
            };
            SlabControls.prototype.mouseOut = function () {
                this.mouseMoveDelta = 0;
                this.lastMousePosition = void 0;
                this.enableWheel = false;
            };
            return SlabControls;
        }());
        Visualization.SlabControls = SlabControls;
        var Camera = /** @class */ (function () {
            function Camera(scene, domElement) {
                this.scene = scene;
                this.domElement = domElement;
                this.fog = new Visualization.THREE.Fog(0x0, 0, 500);
                this.focusPoint = new Visualization.THREE.Vector3(0, 0, 0);
                this.focusRadius = 0;
                this.targetDistance = 0;
                this.nearPlaneDistance = 0;
                this.nearPlaneDelta = 0;
                this.fogEnabled = true;
                this.fogDelta = 0;
                this.observers = [];
                this.setup();
            }
            Camera.shouldInUpdateInclude = function (m) {
                return !isNaN(m.centroid.x) && m.getVisibility();
            };
            Camera.prototype.updateFocus = function (models) {
                if (!models.length)
                    return;
                var sorted = models
                    .filter(function (m) { return Camera.shouldInUpdateInclude(m); })
                    .sort(function (a, b) { return b.radius - a.radius; });
                if (!sorted.length)
                    return;
                var pivots = [sorted[0]];
                var t = new Visualization.THREE.Vector3();
                for (var i = 1; i < sorted.length; i++) {
                    var a = sorted[i];
                    var include = true;
                    for (var _i = 0, pivots_1 = pivots; _i < pivots_1.length; _i++) {
                        var p = pivots_1[_i];
                        var d = t.subVectors(a.centroid, p.centroid).length();
                        if (d < p.radius) {
                            include = false;
                            break;
                        }
                    }
                    if (include) {
                        pivots.push(a);
                    }
                }
                var center = this.focusPoint;
                center.x = 0;
                center.y = 0;
                center.z = 0;
                for (var _a = 0, pivots_2 = pivots; _a < pivots_2.length; _a++) {
                    var p = pivots_2[_a];
                    center.add(p.centroid);
                }
                center.multiplyScalar(1 / pivots.length);
                var radius = 0;
                for (var _b = 0, sorted_1 = sorted; _b < sorted_1.length; _b++) {
                    var m = sorted_1[_b];
                    radius = Math.max(radius, center.distanceTo(m.centroid) + m.radius);
                }
                this.focusRadius = radius;
                this.slabControls.updateRadius(this.focusRadius);
            };
            Camera.prototype.focus = function () {
                this.controls.reset();
                var target = this.focusPoint;
                this.camera.position.set(target.x, target.y, target.z + 4 * this.focusRadius);
                this.camera.lookAt(target);
                this.controls.target.set(target.x, target.y, target.z);
                this.cameraUpdated();
            };
            Camera.prototype.reset = function () {
                this.nearPlaneDelta = 0;
                this.fogDelta = 0;
                this.updateFocus(this.scene.models.all);
                this.focus();
            };
            Camera.prototype.snapshot = function () {
                return this.controls.getState();
            };
            Camera.prototype.restore = function (state) {
                this.controls.setState(state);
                this.scene.forceRender();
            };
            Camera.prototype.focusOnModel = function () {
                var models = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    models[_i] = arguments[_i];
                }
                this.updateFocus(models);
                this.nearPlaneDelta = 0;
                this.fogDelta = 0;
                this.controls.panAndMoveToDistance(this.focusPoint, this.focusRadius * 4);
            };
            Camera.prototype.focusOnPoint = function (center, radius) {
                this.focusPoint.x = center.x;
                this.focusPoint.y = center.y;
                this.focusPoint.z = center.z;
                this.focusRadius = Math.max(radius, 1);
                this.slabControls.updateRadius(this.focusRadius);
                this.nearPlaneDelta = 0;
                this.fogDelta = 0;
                this.controls.panAndMoveToDistance(this.focusPoint, this.focusRadius * 4);
            };
            Camera.prototype.move = function (target) {
                this.controls.panTo(target);
            };
            Camera.prototype.updateSize = function (w, h) {
                var camera = this.camera;
                if (camera instanceof Visualization.THREE.PerspectiveCamera) {
                    camera.aspect = w / h;
                }
                this.slabControls.updateSize(w, h);
                this.camera.updateProjectionMatrix();
                //this.controls.handleResize();
            };
            Object.defineProperty(Camera.prototype, "position", {
                get: function () {
                    return this.camera.position;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(Camera.prototype, "object", {
                get: function () {
                    return this.camera;
                },
                enumerable: true,
                configurable: true
            });
            Camera.prototype.dispose = function () {
                if (this.slabControls) {
                    this.slabControls.destroy();
                    this.slabControls = void 0;
                }
                if (this.unbindCamera) {
                    this.unbindCamera();
                    this.unbindCamera = void 0;
                }
                if (this.controls) {
                    this.controls.destroy();
                    this.controls = void 0;
                }
            };
            Camera.prototype.planeDeltaUpdate = function (delta) {
                var dist = this.computeNearDistance();
                var near = dist + this.nearPlaneDelta + delta;
                if (delta > 0 && near > this.targetDistance)
                    delta = 0;
                if (delta < 0 && near < 0.01)
                    delta = 0;
                this.nearPlaneDelta += delta;
                this.fogDelta += delta;
                this.cameraUpdated();
            };
            Camera.prototype.computeNearDistance = function () {
                var dist = this.controls.target.distanceTo(this.camera.position);
                if (dist > this.focusRadius)
                    return dist - this.focusRadius;
                return 0;
            };
            Camera.prototype.cameraUpdated = function () {
                var options = this.scene.options;
                this.fogEnabled = !!options.enableFog;
                var camera = this.camera;
                if (camera instanceof Visualization.THREE.PerspectiveCamera) {
                    camera.fov = options.cameraFOV;
                }
                this.targetDistance = this.controls.target.distanceTo(this.camera.position);
                var near = this.computeNearDistance() + this.nearPlaneDelta;
                this.camera.near = Math.max(0.01, Math.min(near, this.targetDistance - 0.5));
                if (options.enableFog) {
                    // if (dist + this.focusRadius - this.fogDelta < 1) {
                    //     this.fogDelta = dist + this.focusRadius - 1;
                    // }
                    //   let dist = 0;              
                    // let fogNear = dist + this.focusRadius - this.fogDelta - this.camera.near;
                    // let fogFar = dist + 2 * this.focusRadius - this.fogDelta - this.camera.near;
                    var fogNear = this.targetDistance - this.camera.near + 1 * this.focusRadius - this.nearPlaneDelta;
                    var fogFar = this.targetDistance - this.camera.near + 2 * this.focusRadius - this.nearPlaneDelta;
                    //console.log(fogNear, fogFar); 
                    this.fog.near = Math.max(fogNear, 0.1);
                    this.fog.far = Math.max(fogFar, 0.2);
                }
                else {
                    this.fog.far = 1000001;
                    this.fog.near = 1000000;
                }
                this.camera.updateProjectionMatrix();
                this.scene.forceRender();
                for (var _i = 0, _a = this.observers; _i < _a.length; _i++) {
                    var o = _a[_i];
                    o.call(null, this);
                }
            };
            Camera.prototype.createCamera = function () {
                if (this.scene.options.cameraType === CameraType.Perspective) {
                    this.camera = new Visualization.THREE.PerspectiveCamera(this.scene.options.cameraFOV, this.scene.parentElement.clientWidth / this.scene.parentElement.clientHeight, 0.1, 1000000);
                }
                else {
                    var sw = this.scene.parentElement.clientWidth, sh = this.scene.parentElement.clientHeight;
                    var w = 100, h = sh / sw * w;
                    this.camera = new Visualization.THREE.OrthographicCamera(0.5 * w / -2, 0.5 * w / 2, h / 2, h / -2, 0.1, 1000000);
                }
                if (this.controls) {
                    this.controls.camera = this.camera;
                    this.reset();
                }
            };
            Camera.prototype.setup = function () {
                var _this = this;
                this.dispose();
                this.createCamera();
                this.controls = new Visualization.CameraControls(this.camera, this.domElement, this.scene);
                var cc = this.scene.options.clearColor;
                this.fog.color.setRGB(cc.r, cc.g, cc.b);
                this.scene.scene.fog = this.fog;
                var cameraUpdated = function () { return _this.cameraUpdated(); };
                this.slabControls = new SlabControls(this.domElement);
                var deltaUpdate = this.slabControls.planeDelta.subscribe(function (delta) { return _this.planeDeltaUpdate(delta); });
                this.controls.events.addEventListener('change', cameraUpdated);
                this.unbindCamera = function () {
                    _this.controls.events.removeEventListener('change', cameraUpdated);
                    deltaUpdate.dispose();
                    _this.observers = [];
                };
                this.reset();
            };
            Camera.prototype.observe = function (callback) {
                this.observers.push(callback);
            };
            Camera.prototype.stopObserving = function (callback) {
                this.observers = this.observers.filter(function (o) { return o !== callback; });
            };
            return Camera;
        }());
        Visualization.Camera = Camera;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        Visualization.DefaultSceneOptions = {
            alpha: false,
            clearColor: { r: 0, g: 0, b: 0 },
            cameraSpeed: 6,
            cameraFOV: 30,
            cameraType: Visualization.CameraType.Perspective,
            enableFog: true
        };
        var MouseInfo = /** @class */ (function () {
            function MouseInfo(renderState, domElement) {
                this.renderState = renderState;
                this.domElement = domElement;
                this.position = { x: 0.0, y: 0.0 };
                this.lastPosition = { x: 0.0, y: 0.0 };
                this.isDirty = true;
                this.rect = { left: 0, top: 0, right: 0, bottom: 0 };
                this.exactPosition = { x: 0, y: 0 };
                this.isInside = false;
                this.isButtonDown = false;
            }
            MouseInfo.prototype.updateRect = function () {
                var rect = this.domElement.getBoundingClientRect();
                this.rect.bottom = rect.bottom;
                this.rect.top = rect.top;
                this.rect.left = rect.left;
                this.rect.right = rect.right;
            };
            MouseInfo.prototype.updatePosition = function (clientX, clientY) {
                if (this.position.x === clientX && this.position.y === clientY) {
                    return;
                }
                this.isDirty = true;
                this.position.x = clientX;
                this.position.y = clientY;
            };
            MouseInfo.prototype.update = function () {
                if (this.lastPosition.x === this.position.x
                    && this.lastPosition.y === this.position.y) {
                    return false;
                }
                this.lastPosition.x = this.position.x;
                this.lastPosition.y = this.position.y;
                return true;
            };
            MouseInfo.prototype.setExactPosition = function () {
                if (!this.isDirty) {
                    return;
                }
                var x = Math.round((this.position.x - this.rect.left) / (this.rect.right - this.rect.left) * this.renderState.width) | 0;
                var y = Math.round((this.position.y - this.rect.top) / (this.rect.bottom - this.rect.top) * this.renderState.height) | 0;
                this.exactPosition.x = x;
                this.exactPosition.y = y;
                this.isDirty = false;
            };
            return MouseInfo;
        }());
        Visualization.MouseInfo = MouseInfo;
        var DefaultLighting = /** @class */ (function () {
            function DefaultLighting() {
                this.lights = [];
            }
            DefaultLighting.prototype.setup = function (scene) {
                var pointLight = new Visualization.THREE.PointLight(0xAAAAAA, 0.75);
                scene.add(pointLight);
                this.lights = [pointLight];
                var ambient = new Visualization.THREE.AmbientLight(0x999999);
                scene.add(ambient);
            };
            DefaultLighting.prototype.update = function (cameraPosition) {
                for (var _i = 0, _a = this.lights; _i < _a.length; _i++) {
                    var l = _a[_i];
                    l.position.copy(cameraPosition);
                }
            };
            return DefaultLighting;
        }());
        Visualization.DefaultLighting = DefaultLighting;
        var RenderState = /** @class */ (function () {
            function RenderState() {
                this.width = 0.0;
                this.height = 0.0;
                this.resizing = false;
                this.rendered = false;
                this.lastRenderTime = 0.0;
                this.pickDelta = 0.0;
                this.animationFrame = 0;
            }
            return RenderState;
        }());
        Visualization.RenderState = RenderState;
        var Scene = /** @class */ (function () {
            function Scene(element, options) {
                if (options === void 0) { options = {}; }
                var _this = this;
                this.renderState = new RenderState();
                this.pickInfo = new Visualization.Selection.Pick();
                //private selectInfo: Selection.Info | null = null;
                this.unbindEvents = [];
                this.models = new Visualization.ModelStore(this);
                this.events = new Visualization.THREE.EventDispatcher();
                this.initialResizeTimeout = void 0;
                this.clearHighlightsCall = function () { return _this.clearHighlights(true); };
                this.renderFunc = function (time) { return _this.render(time); };
                this.pickBuffer = new Uint8Array(4);
                options = LiteMol.Core.Utils.extend({}, options, Visualization.DefaultSceneOptions);
                this.options = options;
                this.parentElement = element;
                this.scene = new Visualization.THREE.Scene();
                this.pickScene = new Visualization.THREE.Scene();
                this.pickTarget = new Visualization.THREE.WebGLRenderTarget(1, 1, { format: Visualization.THREE.RGBAFormat, minFilter: Visualization.THREE.LinearFilter });
                this.pickTarget.generateMipmaps = false;
                this.renderer = new Visualization.THREE.WebGLRenderer({ antialias: true, alpha: options.alpha, preserveDrawingBuffer: true });
                this.renderer.setPixelRatio(window.devicePixelRatio || 1);
                this.renderer.setClearColor(new Visualization.THREE.Color(options.clearColor.r, options.clearColor.g, options.clearColor.b));
                this.renderer.autoClear = true;
                this.renderer.sortObjects = false;
                this.mouseInfo = new MouseInfo(this.renderState, this.renderer.domElement);
                // if (!this.options.lighting) this.options.lighting = new DefaultLighting();
                // this.options.lighting.setup(this.scene);
                this.lighting = new DefaultLighting();
                this.lighting.setup(this.scene);
                this.parentElement.appendChild(this.renderer.domElement);
                var delayedResizeHandler = LiteMol.Core.Utils.debounce(function () { return _this.handleResize(); }, 150), resizeHandler = function () {
                    _this.renderState.resizing = true;
                    delayedResizeHandler();
                };
                window.addEventListener('resize', resizeHandler);
                document.addEventListener('resize', resizeHandler);
                this.parentElement.addEventListener('resize', resizeHandler);
                this.unbindEvents.push(function () { return window.removeEventListener('resize', resizeHandler); });
                this.unbindEvents.push(function () { return document.removeEventListener('resize', resizeHandler); });
                this.unbindEvents.push(function () { return _this.parentElement.removeEventListener('resize', resizeHandler); });
                this.setupMouse();
                this.camera = new Visualization.Camera(this, this.renderer.domElement);
                this.handleResize();
                this.renderer.clear();
                this.needsRender();
                this.renderState.animationFrame = requestAnimationFrame(this.renderFunc);
                // sometimes, the renderer DOM element does not initially have the correct size. 
                // This will hopefully fix the issue in most cases.
                this.initialResizeTimeout = setTimeout(function () {
                    _this.initialResizeTimeout = void 0;
                    _this.handleResize();
                }, 1000);
            }
            Scene.prototype.updateOptions = function (options) {
                options = LiteMol.Core.Utils.extend({}, options, this.options);
                var updateCamera = options.cameraType !== this.options.cameraType;
                var cc = options.clearColor;
                this.renderer.setClearColor(new Visualization.THREE.Color(cc.r, cc.g, cc.b));
                this.renderer.setClearAlpha(options.alpha ? 0.0 : 1.0);
                this.camera.fog.color.setRGB(cc.r, cc.g, cc.b);
                if (this.camera.controls) {
                    this.camera.controls.rotateSpeed = options.cameraSpeed;
                    this.camera.controls.zoomSpeed = options.cameraSpeed;
                }
                this.options = options;
                if (updateCamera)
                    this.camera.createCamera();
                this.camera.cameraUpdated();
                this.forceRender();
            };
            Scene.prototype.setupMouse = function () {
                var _this = this;
                var handleMove = function (e) {
                    if (!_this.mouseInfo.isInside) {
                        _this.mouseInfo.updateRect();
                    }
                    _this.mouseInfo.updatePosition(e.clientX, e.clientY);
                    _this.mouseInfo.isInside = true;
                };
                var element = this.renderer.domElement;
                element.addEventListener('mousemove', handleMove);
                this.unbindEvents.push(function () { return element.removeEventListener('mousemove', handleMove); });
                var handleLeave = function (e) {
                    _this.mouseInfo.isInside = false;
                    _this.clearHighlights();
                };
                element.addEventListener('mouseleave', handleLeave);
                this.unbindEvents.push(function () { return element.removeEventListener('mouseleave', handleLeave); });
                var handleDown = function (e) {
                    if (_this.mouseInfo.isInside) {
                        _this.mouseInfo.updateRect();
                        _this.handleSelectStart(e.clientX, e.clientY);
                    }
                    else {
                        //this.selectInfo = null;
                    }
                    _this.mouseInfo.isButtonDown = true;
                    _this.clearHighlights();
                };
                element.addEventListener('mousedown', handleDown);
                this.unbindEvents.push(function () { return element.removeEventListener('mousedown', handleDown); });
                var handleUp = function (e) {
                    _this.mouseInfo.isButtonDown = false;
                    _this.needsRender();
                    _this.handleSelectEnd(e.clientX, e.clientY);
                    _this.clearHighlights(true);
                };
                window.addEventListener('mouseup', handleUp);
                this.unbindEvents.push(function () { return window.removeEventListener('mouseup', handleUp); });
                //let handleTouchStart = (e: TouchEvent) => {
                //    this.handleSelectStart(e.touches[0].clientX, e.touches[0].clientY);
                //};
                //this.parentElement.addEventListener('touchstart', handleTouchStart, false);
                //this.unbindEvents.push(() => this.parentElement.removeEventListener('touchstart', handleTouchStart, false));
                var handleRectUpdate = function (e) {
                    _this.mouseInfo.updateRect();
                };
                window.addEventListener('mousewheel', handleRectUpdate);
                window.addEventListener('DOMMouseScroll', handleRectUpdate); // firefox
                this.unbindEvents.push(function () { return window.removeEventListener('mousewheel', handleRectUpdate); });
                this.unbindEvents.push(function () { return window.removeEventListener('DOMMouseScroll', handleRectUpdate); });
                element.addEventListener('touchstart', handleRectUpdate, false);
                this.unbindEvents.push(function () { return element.removeEventListener('touchstart', handleRectUpdate, false); });
                var handleTouchEnd = function (e) {
                    var touches = e.touches;
                    if (!touches.length) {
                        touches = e.changedTouches;
                    }
                    if (touches.length === 1) {
                        _this.handleSelectEnd(touches[0].clientX, touches[0].clientY);
                    }
                    setTimeout(_this.clearHighlightsCall, 1000 / 15);
                };
                element.addEventListener('touchend', handleTouchEnd, false);
                this.unbindEvents.push(function () { return element.removeEventListener('touchend', handleTouchEnd, false); });
                try {
                    element.addEventListener('touchcancel', handleTouchEnd, false);
                    this.unbindEvents.push(function () { return element.removeEventListener('touchcancel', handleTouchEnd, false); });
                }
                catch (e) {
                }
            };
            Scene.prototype.handleSelectStart = function (x, y) {
                this.pickInfo.selectStart(x, y);
                //this.selectInfo = this.pickInfo.getPickInfo();
            };
            Scene.prototype.handleSelectEnd = function (x, y) {
                if (this.pickInfo.selectEnd(x, y)) {
                    var info = this.handlePick(true);
                    this.dispatchSelectEvent(info);
                }
                // this.selectInfo = null;
            };
            Scene.prototype.handleResize = function () {
                var w = this.parentElement.clientWidth, h = this.parentElement.clientHeight;
                this.camera.updateSize(w, h);
                if (this.renderState.height === h && this.renderState.width === w) {
                    this.renderState.resizing = false;
                    return;
                }
                this.renderState.width = w;
                this.renderState.height = h;
                this.renderer.setSize(w, h);
                this.pickTarget = new Visualization.THREE.WebGLRenderTarget(w, h, { format: Visualization.THREE.RGBAFormat, minFilter: Visualization.THREE.LinearFilter });
                this.pickTarget.generateMipmaps = false;
                this.renderState.resizing = false;
                this.mouseInfo.updateRect();
                this.needsRender();
            };
            Scene.prototype.needsRender = function () {
                this.renderState.rendered = false;
            };
            Scene.prototype.checkDirty = function () {
                var dirty = false;
                for (var _i = 0, _a = this.models.all; _i < _a.length; _i++) {
                    var m = _a[_i];
                    dirty = dirty || m.dirty;
                    m.dirty = false;
                }
                return dirty;
            };
            Scene.prototype.render = function (time) {
                if (this.renderState.resizing) {
                    this.renderState.animationFrame = requestAnimationFrame(this.renderFunc);
                    return;
                }
                var delta = time - this.renderState.lastRenderTime;
                this.renderState.pickDelta += delta;
                this.renderState.lastRenderTime = time;
                if (this.renderState.pickDelta > 33.3333333 /* 30 fps */) {
                    this.renderState.pickDelta = this.renderState.pickDelta % 33.3333333;
                    this.handlePick(false);
                }
                var dirty = this.checkDirty();
                if (dirty)
                    this.renderState.rendered = false;
                if (!this.renderState.rendered) {
                    this.lighting.update(this.camera.position);
                    this.renderer.sortObjects = true;
                    this.renderer.render(this.scene, this.camera.object);
                    this.renderer.sortObjects = false;
                    this.renderState.rendered = true;
                    if (!this.mouseInfo.isButtonDown) {
                        this.renderer.setClearAlpha(1.0);
                        this.renderer.render(this.pickScene, this.camera.object, this.pickTarget);
                        this.renderer.setClearAlpha(this.options.alpha ? 0.0 : 1.0);
                    }
                }
                this.renderState.animationFrame = requestAnimationFrame(this.renderFunc);
            };
            Scene.prototype.dispatchHoverEvent = function () {
                this.events.dispatchEvent({ type: Scene.hoverEvent, target: null, data: this.pickInfo.getPickInfo() });
            };
            Scene.prototype.dispatchSelectEvent = function (info) {
                if (info) {
                    this.events.dispatchEvent({ type: Scene.selectEvent, target: null, data: info });
                }
            };
            Scene.prototype.clearHighlights = function (update) {
                if (update === void 0) { update = true; }
                var info = this.pickInfo, model = this.models.getBySceneId(info.currentPickId), changed = false;
                if (model) {
                    changed = model.highlightElement(info.currentPickElementId, false);
                }
                if (changed && update)
                    this.needsRender();
                if (this.pickInfo.reset()) {
                    this.dispatchHoverEvent();
                }
                return changed;
            };
            Scene.prototype.handlePick = function (isSelect) {
                if (!isSelect && (!this.mouseInfo.update() || this.mouseInfo.isButtonDown) || this.renderState.resizing) {
                    return;
                }
                if (!this.mouseInfo.isInside) {
                    return void 0;
                }
                this.mouseInfo.setExactPosition();
                var position = this.mouseInfo.exactPosition;
                var cY = this.pickTarget.height - position.y;
                if (this.pickTarget.width < position.x - 1 || position.x < 0.01 ||
                    this.pickTarget.height < cY - 1 || cY < 0.01) {
                    return void 0;
                }
                this.renderer.readRenderTargetPixels(this.pickTarget, position.x | 0, cY | 0, 1, 1, this.pickBuffer);
                var id = Visualization.Selection.Picking.getSceneId(this.models.idWidth, this.pickBuffer), pickId = Visualization.Selection.Picking.getElementId(this.models.idWidth, this.pickBuffer), info = this.pickInfo;
                if (isSelect) {
                    if (id === 255)
                        return void 0;
                    var model = this.models.getBySceneId(id);
                    if (!model)
                        return void 0;
                    return { model: model, elements: model.getPickElements(pickId) };
                }
                else {
                    if (id === info.currentPickId && pickId === info.currentPickElementId)
                        return void 0;
                    var changed = this.clearHighlights(false), model = this.models.getBySceneId(id);
                    if (id === 255 || !model) {
                        if (changed)
                            this.needsRender();
                        return void 0;
                    }
                    info.currentPickId = id;
                    info.currentPickElementId = pickId;
                    if (model.highlightElement(pickId, true) || changed) {
                        this.needsRender();
                        info.current = { model: model, elements: model.getPickElements(pickId) };
                        this.dispatchHoverEvent();
                    }
                    return void 0;
                }
            };
            Scene.prototype.resized = function () {
                this.handleResize();
            };
            Scene.prototype.forceRender = function () {
                this.needsRender();
            };
            Scene.prototype.clear = function () {
                this.models.clear();
            };
            Scene.prototype.downloadScreenshot = function () {
                var uri = this.renderer.domElement.toDataURL('image/png');
                var a = document.createElement('a');
                if ('download' in a) {
                    a.style.visibility = 'hidden';
                    a.href = uri;
                    a.target = '_blank';
                    a.download = 'litemol_screenshot.png';
                    document.body.appendChild(a);
                    a.click();
                    a.remove();
                }
                else {
                    window.open(uri, '_blank');
                }
            };
            Scene.prototype.destroy = function () {
                //clearInterval(this.updateSizeInterval);
                this.clear();
                for (var _i = 0, _a = this.unbindEvents; _i < _a.length; _i++) {
                    var e = _a[_i];
                    try {
                        e();
                    }
                    catch (_ex) { }
                }
                if (this.initialResizeTimeout !== void 0) {
                    clearTimeout(this.initialResizeTimeout);
                    this.initialResizeTimeout = void 0;
                }
                this.unbindEvents = [];
                cancelAnimationFrame(this.renderState.animationFrame);
                this.scene = null;
                this.pickScene = null;
                this.camera.dispose();
                this.camera = null;
                if (this.renderer && this.renderer.dispose)
                    this.renderer.dispose();
                this.renderer = null;
                this.pickTarget.dispose();
                this.pickTarget = null;
                while (this.parentElement.lastChild)
                    this.parentElement.removeChild(this.parentElement.lastChild);
            };
            Scene.hoverEvent = 'hover';
            Scene.selectEvent = 'select';
            return Scene;
        }());
        Visualization.Scene = Scene;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        ;
        // ported and modified from threejs Trackball Controls
        var CameraControls = /** @class */ (function () {
            function CameraControls(camera, domElement, scene) {
                var _this = this;
                this.camera = camera;
                this.domElement = domElement;
                this.scene = scene;
                this.enabled = true;
                //private screen = { left: 0, top: 0, width: 0, height: 0 };
                this.rotateSpeed = 6;
                this.zoomSpeed = 6;
                this.panSpeed = 1.0;
                this.noRotate = false;
                this.noZoom = false;
                this.noPan = false;
                this.noRoll = true;
                this.staticMoving = true;
                this.dynamicDampingFactor = 0.2;
                this.minDistance = 1.5;
                this.maxDistance = 100000;
                this.keys = [65 /*A*/, 16 /*S*/, 17 /*D*/];
                this.target = new Visualization.THREE.Vector3();
                // internals
                this.EPS = 0.000001;
                this.lastPosition = new Visualization.THREE.Vector3();
                this._state = -1 /* NONE */;
                this._keyDownState = -1 /* NONE */;
                this._prevState = -1 /* NONE */;
                this._eye = new Visualization.THREE.Vector3();
                this._rotateStart = new Visualization.THREE.Vector3();
                this._rotateEnd = new Visualization.THREE.Vector3();
                this._zoomStart = new Visualization.THREE.Vector2();
                this._zoomEnd = new Visualization.THREE.Vector2();
                this._touchZoomDistanceStart = 0;
                this._touchZoomDistanceEnd = 0;
                this._panStart = new Visualization.THREE.Vector2();
                this._panEnd = new Visualization.THREE.Vector2();
                // for reset
                this.target0 = this.target.clone();
                this.position0 = this.camera.position.clone();
                this.up0 = this.camera.up.clone();
                // events
                this.changeEvent = { type: 'change', target: void 0 };
                this.startEvent = { type: 'start', target: void 0 };
                this.endEvent = { type: 'end', target: void 0 };
                this.events = new Visualization.THREE.EventDispatcher();
                this._mouseOnScreen = new Visualization.THREE.Vector2();
                this._mouseOnBallProjection = new Visualization.THREE.Vector3();
                this._objectUp = new Visualization.THREE.Vector3();
                this._mouseOnBall = new Visualization.THREE.Vector3();
                this._rotationAxis = new Visualization.THREE.Vector3();
                this._rotationQuaternion = new Visualization.THREE.Quaternion();
                this._panMouseChange = new Visualization.THREE.Vector2();
                this._panObjectUp = new Visualization.THREE.Vector3();
                this._panPan = new Visualization.THREE.Vector3();
                this._panToDelta = new Visualization.THREE.Vector3();
                this._panToVector = new Visualization.THREE.Vector3();
                this.eventHandlers = {
                    'keydown': function (event) { return _this.keydown(event); },
                    'keyup': function (event) { return _this.keyup(event); },
                    'mousedown': function (event) { return _this.mousedown(event); },
                    'mouseup': function (event) { return _this.mouseup(event); },
                    'mousemove': function (event) { return _this.mousemove(event); },
                    'touchstart': function (event) { return _this.touchstart(event); },
                    'touchmove': function (event) { return _this.touchmove(event); },
                    'touchend': function (event) { return _this.touchend(event); }
                };
                this.init();
            }
            CameraControls.prototype.getMouseOnScreen = function () {
                this.scene.mouseInfo.setExactPosition();
                var rs = this.scene.renderState, pos = this.scene.mouseInfo.exactPosition;
                this._mouseOnScreen.set(pos.x / rs.width, pos.y / rs.height);
                return this._mouseOnScreen;
            };
            CameraControls.prototype.getMouseProjectionOnBall = function () {
                this.scene.mouseInfo.setExactPosition();
                var rs = this.scene.renderState, pos = this.scene.mouseInfo.exactPosition;
                var cX = 0.5 * rs.width, cY = 0.5 * rs.height, u = (pos.x - cX) / (rs.width * .5), v = -(pos.y - cY) / (rs.height * .5);
                this._mouseOnBall.set(u, v, 0.0);
                var length = this._mouseOnBall.length();
                if (this.noRoll) {
                    if (length < Math.SQRT1_2) {
                        this._mouseOnBall.z = Math.sqrt(1.0 - length * length);
                    }
                    else {
                        this._mouseOnBall.z = .5 / length;
                    }
                }
                else if (length > 1.0) {
                    this._mouseOnBall.normalize();
                }
                else {
                    this._mouseOnBall.z = Math.sqrt(1.0 - length * length);
                }
                this._eye.copy(this.camera.position).sub(this.target);
                this._mouseOnBallProjection.copy(this.camera.up).setLength(this._mouseOnBall.y);
                this._mouseOnBallProjection.add(this._objectUp.copy(this.camera.up).cross(this._eye).setLength(this._mouseOnBall.x));
                this._mouseOnBallProjection.add(this._eye.setLength(this._mouseOnBall.z));
                return this._mouseOnBallProjection;
            };
            CameraControls.prototype.rotateCamera = function () {
                var angle = Math.acos(this._rotateStart.dot(this._rotateEnd) / this._rotateStart.length() / this._rotateEnd.length());
                if (angle) {
                    this._rotationAxis.crossVectors(this._rotateStart, this._rotateEnd).normalize();
                    angle *= this.rotateSpeed;
                    this._rotationQuaternion.setFromAxisAngle(this._rotationAxis, -angle);
                    this._eye.applyQuaternion(this._rotationQuaternion);
                    this.camera.up.applyQuaternion(this._rotationQuaternion);
                    this._rotateEnd.applyQuaternion(this._rotationQuaternion);
                    if (this.staticMoving) {
                        this._rotateStart.copy(this._rotateEnd);
                    }
                    else {
                        this._rotationQuaternion.setFromAxisAngle(this._rotationAxis, angle * (this.dynamicDampingFactor - 1.0));
                        this._rotateStart.applyQuaternion(this._rotationQuaternion);
                    }
                }
            };
            CameraControls.prototype.zoomCamera = function () {
                if (this._state === 4 /* TOUCH_ZOOM_PAN */) {
                    var factor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd;
                    this._touchZoomDistanceStart = this._touchZoomDistanceEnd;
                    this._eye.multiplyScalar(factor);
                }
                else {
                    var factor = 1.0 - (this._zoomEnd.y - this._zoomStart.y) * this.zoomSpeed;
                    if (factor !== 1.0 && factor > 0.0) {
                        this._eye.multiplyScalar(factor);
                        if (this.staticMoving) {
                            this._zoomStart.copy(this._zoomEnd);
                        }
                        else {
                            this._zoomStart.y += (this._zoomEnd.y - this._zoomStart.y) * this.dynamicDampingFactor;
                        }
                    }
                }
            };
            ;
            CameraControls.prototype.panCamera = function () {
                this._panMouseChange.copy(this._panEnd).sub(this._panStart);
                if (this._panMouseChange.lengthSq()) {
                    this._panMouseChange.multiplyScalar(this._eye.length() * this.panSpeed);
                    this._panPan.copy(this._eye).cross(this.camera.up).setLength(this._panMouseChange.x);
                    this._panPan.add(this._panObjectUp.copy(this.camera.up).setLength(this._panMouseChange.y));
                    this.camera.position.add(this._panPan);
                    this.target.add(this._panPan);
                    if (this.staticMoving) {
                        this._panStart.copy(this._panEnd);
                    }
                    else {
                        this._panStart.add(this._panMouseChange.subVectors(this._panEnd, this._panStart).multiplyScalar(this.dynamicDampingFactor));
                    }
                }
            };
            CameraControls.prototype.panTo = function (_a) {
                var x = _a.x, y = _a.y, z = _a.z;
                this._panToVector.set(x, y, z);
                this._panToDelta.subVectors(this._panToVector, this.target);
                this.camera.position.add(this._panToDelta);
                this.camera.lookAt(this._panToVector);
                this.target.copy(this._panToVector);
                this._eye.subVectors(this.camera.position, this.target);
                this.lastPosition.copy(this.camera.position);
                if (this._panToDelta.lengthSq() > this.EPS) {
                    this.events.dispatchEvent(this.changeEvent);
                }
            };
            CameraControls.prototype.panAndMoveToDistance = function (_a, distance) {
                var x = _a.x, y = _a.y, z = _a.z;
                this._panToVector.set(x, y, z);
                this._panToDelta.subVectors(this._panToVector, this.target);
                this.camera.position.add(this._panToDelta);
                this.camera.lookAt(this._panToVector);
                this.target.copy(this._panToVector);
                this._eye.subVectors(this.camera.position, this.target);
                this._eye.setLength(distance);
                this.camera.position.addVectors(this.target, this._eye);
                this.checkDistances();
                this.lastPosition.copy(this.camera.position);
                this.events.dispatchEvent(this.changeEvent);
            };
            CameraControls.prototype.checkDistances = function () {
                if (!this.noZoom || !this.noPan) {
                    if (this._eye.lengthSq() > this.maxDistance * this.maxDistance) {
                        this.camera.position.addVectors(this.target, this._eye.setLength(this.maxDistance));
                    }
                    if (this._eye.lengthSq() < this.minDistance * this.minDistance) {
                        this.camera.position.addVectors(this.target, this._eye.setLength(this.minDistance));
                    }
                }
            };
            CameraControls.prototype.update = function () {
                this._eye.subVectors(this.camera.position, this.target);
                if (!this.noRotate) {
                    this.rotateCamera();
                }
                if (!this.noZoom) {
                    this.zoomCamera();
                }
                if (!this.noPan) {
                    this.panCamera();
                }
                this.camera.position.addVectors(this.target, this._eye);
                this.checkDistances();
                this.camera.lookAt(this.target);
                if (this.lastPosition.distanceToSquared(this.camera.position) > this.EPS) {
                    this.events.dispatchEvent(this.changeEvent);
                    this.lastPosition.copy(this.camera.position);
                }
            };
            CameraControls.prototype.reset = function () {
                this._state = -1 /* NONE */;
                this._prevState = -1 /* NONE */;
                this.target.copy(this.target0);
                this.camera.position.copy(this.position0);
                this.camera.up.copy(this.up0);
                this._eye.subVectors(this.camera.position, this.target);
                this.camera.lookAt(this.target);
                this.events.dispatchEvent(this.changeEvent);
                this.lastPosition.copy(this.camera.position);
            };
            CameraControls.prototype.getState = function () {
                return {
                    state: this._state,
                    prevState: this._prevState,
                    target: this.target.clone(),
                    objPos: this.camera.position.clone(),
                    objUp: this.camera.up.clone(),
                    eye: this._eye.clone(),
                    lastPosition: this.lastPosition.clone()
                };
            };
            CameraControls.prototype.setState = function (state) {
                this._state = state.state;
                this._prevState = state.prevState;
                this.target.copy(state.target);
                this.camera.position.copy(state.objPos);
                this.camera.up.copy(state.objUp);
                this._eye.copy(state.eye);
                this.camera.lookAt(this.target);
                this.events.dispatchEvent(this.changeEvent);
                this.lastPosition.copy(state.lastPosition);
            };
            CameraControls.prototype.keydown = function (event) {
                if (this.enabled === false)
                    return;
                window.removeEventListener('keydown', this.eventHandlers.keydown, false);
                window.addEventListener('keyup', this.eventHandlers.keyup, false);
                this._prevState = this._state;
                if (this._state !== -1 /* NONE */) {
                    return;
                }
                else if (event.keyCode === this.keys[0 /* ROTATE */] && !this.noRotate) {
                    this._state = 0 /* ROTATE */;
                }
                else if (event.keyCode === this.keys[2 /* ZOOM */] && !this.noZoom) {
                    this._state = 2 /* ZOOM */;
                }
                else if (event.keyCode === this.keys[1 /* PAN */] && !this.noPan) {
                    this._state = 1 /* PAN */;
                }
                this._keyDownState = this._state;
            };
            CameraControls.prototype.keyup = function (event) {
                if (this.enabled === false)
                    return;
                this._state = this._prevState;
                this._keyDownState = -1 /* NONE */;
                window.removeEventListener('keyup', this.eventHandlers.keyup, false);
                window.addEventListener('keydown', this.eventHandlers.keydown, false);
            };
            CameraControls.prototype.mousedown = function (event) {
                if (this.enabled === false)
                    return;
                event.preventDefault();
                //event.stopPropagation();
                this.scene.mouseInfo.updatePosition(event.clientX, event.clientY);
                if (this._keyDownState !== -1 /* NONE */) {
                    this._state = this._keyDownState;
                }
                if (this._state === -1 /* NONE */) {
                    this._state = event.button;
                }
                if (this._state === 0 /* ROTATE */ && !this.noRotate) {
                    this._rotateStart.copy(this.getMouseProjectionOnBall());
                    this._rotateEnd.copy(this._rotateStart);
                }
                else if (this._state === 2 /* ZOOM */ && !this.noZoom) {
                    this._zoomStart.copy(this.getMouseOnScreen());
                    this._zoomEnd.copy(this._zoomStart);
                }
                else if (this._state === 1 /* PAN */ && !this.noPan) {
                    this._panStart.copy(this.getMouseOnScreen());
                    this._panEnd.copy(this._panStart);
                }
                window.addEventListener('mousemove', this.eventHandlers.mousemove, false);
                window.addEventListener('mouseup', this.eventHandlers.mouseup, false);
                this.events.dispatchEvent(this.startEvent);
            };
            CameraControls.prototype.mousemove = function (event) {
                if (this.enabled === false)
                    return;
                event.preventDefault();
                this.scene.mouseInfo.updatePosition(event.clientX, event.clientY);
                //event.stopPropagation();
                if (this._state === 0 /* ROTATE */ && !this.noRotate) {
                    this._rotateEnd.copy(this.getMouseProjectionOnBall());
                }
                else if (this._state === 2 /* ZOOM */ && !this.noZoom) {
                    this._zoomEnd.copy(this.getMouseOnScreen());
                }
                else if (this._state === 1 /* PAN */ && !this.noPan) {
                    this._panEnd.copy(this.getMouseOnScreen());
                }
                this.update();
            };
            CameraControls.prototype.mouseup = function (event) {
                if (this.enabled === false)
                    return;
                event.preventDefault();
                //event.stopPropagation();
                this._state = -1 /* NONE */;
                window.removeEventListener('mousemove', this.eventHandlers.mousemove, false);
                window.removeEventListener('mouseup', this.eventHandlers.mouseup, false);
                this.events.dispatchEvent(this.endEvent);
            };
            CameraControls.prototype.touchstart = function (event) {
                //console.log("trouch start");
                if (this.enabled === false)
                    return;
                switch (event.touches.length) {
                    case 1:
                        this._state = 3 /* TOUCH_ROTATE */;
                        this.scene.mouseInfo.updatePosition(event.touches[0].clientX, event.touches[0].clientY);
                        this._rotateStart.copy(this.getMouseProjectionOnBall( /*event.touches[0].clientX, event.touches[0].clientY*/));
                        this._rotateEnd.copy(this._rotateStart);
                        break;
                    case 2:
                        this._state = 4 /* TOUCH_ZOOM_PAN */;
                        var dx = event.touches[0].clientX - event.touches[1].clientX;
                        var dy = event.touches[0].clientY - event.touches[1].clientY;
                        this._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy);
                        var x = (event.touches[0].clientX + event.touches[1].clientX) / 2;
                        var y = (event.touches[0].clientY + event.touches[1].clientY) / 2;
                        this.scene.mouseInfo.updatePosition(x, y);
                        this._panStart.copy(this.getMouseOnScreen( /*x, y*/));
                        this._panEnd.copy(this._panStart);
                        break;
                    default:
                        this._state = -1 /* NONE */;
                }
                this.events.dispatchEvent(this.startEvent);
            };
            CameraControls.prototype.touchmove = function (event) {
                if (this.enabled === false)
                    return;
                event.preventDefault();
                event.stopPropagation();
                switch (event.touches.length) {
                    case 1:
                        this.scene.mouseInfo.updatePosition(event.touches[0].clientX, event.touches[0].clientY);
                        this._rotateEnd.copy(this.getMouseProjectionOnBall( /*event.touches[0].clientX, event.touches[0].clientY*/));
                        this.update();
                        break;
                    case 2:
                        var dx = event.touches[0].clientX - event.touches[1].clientX;
                        var dy = event.touches[0].clientY - event.touches[1].clientY;
                        this._touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy);
                        var x = (event.touches[0].clientX + event.touches[1].clientX) / 2;
                        var y = (event.touches[0].clientY + event.touches[1].clientY) / 2;
                        this.scene.mouseInfo.updatePosition(x, y);
                        this._panEnd.copy(this.getMouseOnScreen( /*x, y*/));
                        this.update();
                        break;
                    default:
                        this._state = -1 /* NONE */;
                }
            };
            CameraControls.prototype.touchend = function (event) {
                if (this.enabled === false)
                    return;
                var touches = event.touches;
                if (!touches.length) {
                    touches = event.changedTouches;
                }
                switch (touches.length) {
                    case 1:
                        this.scene.mouseInfo.updatePosition(touches[0].clientX, touches[0].clientY);
                        this._rotateEnd.copy(this.getMouseProjectionOnBall( /*event.touches[0].clientX, event.touches[0].clientY*/));
                        this._rotateStart.copy(this._rotateEnd);
                        break;
                    case 2:
                        this._touchZoomDistanceStart = this._touchZoomDistanceEnd = 0;
                        var x = (touches[0].clientX + touches[1].clientX) / 2;
                        var y = (touches[0].clientY + touches[1].clientY) / 2;
                        this.scene.mouseInfo.updatePosition(x, y);
                        this._panEnd.copy(this.getMouseOnScreen( /*x, y*/));
                        this._panStart.copy(this._panEnd);
                        break;
                }
                this._state = -1 /* NONE */;
                this.events.dispatchEvent(this.endEvent);
            };
            CameraControls.prototype.preventContextMenu = function (event) { event.preventDefault(); };
            CameraControls.prototype.init = function () {
                this.domElement.addEventListener('contextmenu', this.preventContextMenu, false);
                this.domElement.addEventListener('mousedown', this.eventHandlers.mousedown, false);
                //this.domElement.addEventListener('mousewheel', mousewheel, false);
                //this.domElement.addEventListener('DOMMouseScroll', mousewheel, false); // firefox
                this.domElement.addEventListener('touchstart', this.eventHandlers.touchstart, false);
                this.domElement.addEventListener('touchend', this.eventHandlers.touchend, false);
                this.domElement.addEventListener('touchmove', this.eventHandlers.touchmove, false);
                window.addEventListener('keydown', this.eventHandlers.keydown, false);
                // window.addEventListener('keyup', keyup, false);
                //this.handleResize();
                // force an update at start
                this.update();
            };
            CameraControls.prototype.destroy = function () {
                this.domElement.removeEventListener('contextmenu', this.preventContextMenu, false);
                this.domElement.removeEventListener('mousedown', this.eventHandlers.mousedown, false);
                //scope.domElement.removeEventListener('mousewheel', onMouseWheel, false);
                //scope.domElement.removeEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
                //scope.domElement.removeEventListener('keydown', keydown, false);
                window.removeEventListener('keydown', this.eventHandlers.keydown, false);
                //scope.domElement.removeEventListener('keyup', keyup, false);
                this.domElement.removeEventListener('touchstart', this.eventHandlers.touchstart, false);
                this.domElement.removeEventListener('touchend', this.eventHandlers.touchend, false);
                this.domElement.removeEventListener('touchmove', this.eventHandlers.touchmove, false);
                this.camera = void 0;
                this.domElement = void 0;
            };
            ;
            return CameraControls;
        }());
        Visualization.CameraControls = CameraControls;
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Selection;
        (function (Selection) {
            var Pick = /** @class */ (function () {
                function Pick() {
                    this.current = null;
                    this.currentPickId = -1;
                    this.currentPickElementId = -1;
                    this.selectPos = { x: 0.0, y: 0.0 };
                }
                Pick.prototype.getPickInfo = function () {
                    if (!this.current)
                        return this.current;
                    if (this.current.elements && !this.current.elements.length)
                        return null;
                    return {
                        model: this.current.model,
                        elements: this.current.elements,
                    };
                };
                Pick.prototype.reset = function () {
                    var changed = this.current !== null;
                    this.currentPickId = -1;
                    this.currentPickElementId = -1;
                    this.current = null;
                    return changed;
                };
                Pick.prototype.selectStart = function (x, y) {
                    this.selectPos.x = x;
                    this.selectPos.y = y;
                };
                Pick.prototype.selectEnd = function (x, y) {
                    var dx = x - this.selectPos.x, dy = y - this.selectPos.y;
                    return dx * dx + dy * dy < 4.5;
                };
                return Pick;
            }());
            Selection.Pick = Pick;
            var Picking;
            (function (Picking) {
                function assignPickColor(elementId, color) {
                    var b = (elementId >> 16) & 0xFF, g = (elementId >> 8) & 0xFF, r = elementId & 0xFF;
                    color.r = r / 255.0;
                    color.g = g / 255.0;
                    color.b = b / 255.0;
                }
                Picking.assignPickColor = assignPickColor;
                function applySceneIdFast(id, offset, data) {
                    data[offset + 3] = id / 255.0;
                }
                Picking.applySceneIdFast = applySceneIdFast;
                function applySceneIdSlow(extraBits, id, offset, data) {
                    var low = (id & ((1 << extraBits) - 1)) << (8 - extraBits);
                    var high = id >> extraBits;
                    data[offset + 3] = high / 255.0;
                    var v = (data[offset + 2] * 255) | 0;
                    data[offset + 2] = (v | low) / 255.0;
                }
                Picking.applySceneIdSlow = applySceneIdSlow;
                function getElementId(idWidth, buffer) {
                    var mask = (1 << (16 - idWidth)) - 1;
                    return buffer[0] | (buffer[1] << 8) | ((buffer[2] & mask) << 16);
                }
                Picking.getElementId = getElementId;
                function getSceneId(idWidth, buffer) {
                    var extraBits = idWidth - 8;
                    var low = (buffer[2] & (((1 << extraBits) - 1) << (8 - extraBits)) >> (8 - extraBits));
                    var high = buffer[3] << extraBits;
                    return low | high;
                }
                Picking.getSceneId = getSceneId;
            })(Picking = Selection.Picking || (Selection.Picking = {}));
            ;
            var ChunkedArray = LiteMol.Core.Utils.ChunkedArray;
            var VertexMapBuilder = /** @class */ (function () {
                function VertexMapBuilder(elementCount) {
                    this.elementMap = LiteMol.Core.Utils.FastMap.create();
                    this.elementIndex = 0;
                    this.elementRangeIndex = 0;
                    this.rangeIndex = 0;
                    this.added = 0;
                    this.elementIndices = ChunkedArray.create(function (size) { return new Int32Array(size); }, elementCount, 1);
                    this.elementRanges = new Int32Array(2 * elementCount);
                    this.vertexRanges = ChunkedArray.create(function (size) { return new Int32Array(size); }, elementCount, 2);
                }
                VertexMapBuilder.prototype.startElement = function (index) {
                    this.elementIndex = index;
                    this.elementRangeIndex = this.elementMap.size;
                    this.rangeIndex = this.vertexRanges.elementCount;
                    this.added = 0;
                };
                VertexMapBuilder.prototype.addVertexRange = function (start, end) {
                    this.added++;
                    ChunkedArray.add2(this.vertexRanges, start, end);
                };
                VertexMapBuilder.prototype.endElement = function () {
                    ChunkedArray.add(this.elementIndices, this.elementIndex);
                    this.elementMap.set(this.elementIndex, this.elementRangeIndex);
                    this.elementRanges[2 * this.elementRangeIndex] = 2 * this.rangeIndex;
                    this.elementRanges[2 * this.elementRangeIndex + 1] = 2 * (this.rangeIndex + this.added);
                };
                VertexMapBuilder.prototype.getMap = function () {
                    return new VertexMap(ChunkedArray.compact(this.elementIndices), this.elementMap, this.elementRanges, ChunkedArray.compact(this.vertexRanges));
                };
                return VertexMapBuilder;
            }());
            Selection.VertexMapBuilder = VertexMapBuilder;
            var VertexMap = /** @class */ (function () {
                function VertexMap(elementIndices, elementMap, elementRanges, vertexRanges) {
                    this.elementIndices = elementIndices;
                    this.elementMap = elementMap;
                    this.elementRanges = elementRanges;
                    this.vertexRanges = vertexRanges;
                }
                return VertexMap;
            }());
            Selection.VertexMap = VertexMap;
            function applyActionToRange(array, start, end, action) {
                var changed = false;
                if (action === 3 /* Highlight */) {
                    for (var i = start; i < end; i++) {
                        var v = array[i];
                        var c = (v | 0);
                        if (v - c < 0.33) {
                            array[i] = c + 0.55;
                            changed = true;
                        }
                    }
                }
                else if (action === 4 /* RemoveHighlight */) {
                    for (var i = start; i < end; i++) {
                        var v = array[i];
                        var c = (v | 0);
                        if (v - c > 0.33) {
                            array[i] = c;
                            changed = true;
                        }
                    }
                }
                else if (action === 1 /* Select */) {
                    for (var i = start; i < end; i++) {
                        array[i] = array[i] + 1;
                        changed = true;
                    }
                }
                else if (action === 2 /* RemoveSelect */) {
                    for (var i = start; i < end; i++) {
                        if (array[i] > 0.75) {
                            var v = array[i] - 1;
                            if (v < 0)
                                v = 0;
                            array[i] = v;
                            changed = true;
                        }
                    }
                }
                else { // clear
                    for (var i = start; i < end; i++) {
                        var v = array[i];
                        array[i] = 0;
                        changed = changed || v !== 0;
                    }
                }
                return changed;
            }
            Selection.applyActionToRange = applyActionToRange;
            function applyActionToBuffer(buffer, action) {
                var array = buffer.array;
                var ret = applyActionToRange(array, 0, array.length, action);
                if (ret)
                    buffer.needsUpdate = true;
                return ret;
            }
            Selection.applyActionToBuffer = applyActionToBuffer;
        })(Selection = Visualization.Selection || (Visualization.Selection = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Geometry;
        (function (Geometry) {
            "use strict";
            function toBufferGeometry(raw) {
                var geometry = new Visualization.THREE.BufferGeometry();
                geometry.addAttribute('position', new Visualization.THREE.BufferAttribute(raw.vertices, 3));
                if (raw.normals) {
                    geometry.addAttribute('normal', new Visualization.THREE.BufferAttribute(raw.normals, 3));
                }
                geometry.addAttribute('index', new Visualization.THREE.BufferAttribute(raw.indices, 1));
                return geometry;
            }
            Geometry.toBufferGeometry = toBufferGeometry;
            function addAttribute(geom, name, a, elementSize) {
                geom.addAttribute(name, new Visualization.THREE.BufferAttribute(a, elementSize));
            }
            Geometry.addAttribute = addAttribute;
            var CoreUtils = LiteMol.Core.Utils;
            var ChunkedArray = CoreUtils.ChunkedArray;
            var ArrayBuilder = CoreUtils.ArrayBuilder;
            var Builder;
            (function (Builder) {
                function createStatic(vertexCount, indexCount, elementSize) {
                    if (elementSize === void 0) { elementSize = 3; }
                    return {
                        type: 'Static',
                        vertices: ArrayBuilder.create(function (s) { return new Float32Array(s); }, vertexCount, 3),
                        indices: ArrayBuilder.create(function (s) { return new Uint32Array(s); }, indexCount, elementSize),
                        normals: elementSize === 3 ? ArrayBuilder.create(function (s) { return new Float32Array(s); }, vertexCount, 3) : void 0,
                        elementSize: elementSize
                    };
                }
                Builder.createStatic = createStatic;
                function createDynamic(vertexChunkSize, indexChunkSize, elementSize) {
                    if (elementSize === void 0) { elementSize = 3; }
                    return {
                        type: 'Dynamic',
                        vertices: ChunkedArray.create(function (s) { return new Float32Array(s); }, vertexChunkSize, 3),
                        indices: ChunkedArray.create(function (s) { return new Uint32Array(s); }, indexChunkSize, elementSize),
                        normals: elementSize === 3 ? ChunkedArray.create(function (s) { return new Float32Array(s); }, vertexChunkSize, 3) : void 0,
                        elementSize: elementSize
                    };
                }
                Builder.createDynamic = createDynamic;
                var add2d = ChunkedArray.add2;
                var add3d = ChunkedArray.add3;
                var add2s = ArrayBuilder.add2;
                var add3s = ArrayBuilder.add3;
                var Geom = LiteMol.Core.Geometry;
                var Vec3 = Geom.LinearAlgebra.Vector3;
                var Mat4 = Geom.LinearAlgebra.Matrix4;
                // function copy3(src: ArrayLike<number>, tar: ChunkedArray<number> | ArrayBuilder<number>, add: (a: ChunkedArray<number> | ArrayBuilder<number>, x: number, y: number, z: number) => void) {
                //     for (let i = 0, __i = src.length; i < __i; i += 3) {
                //         add(tar, src[i], src[i + 1], src[i + 2]);
                //     }
                // }
                function copy3o(offset, src, tar, add) {
                    for (var i = 0, __i = src.length; i < __i; i += 3) {
                        add(tar, src[i] + offset, src[i + 1] + offset, src[i + 2] + offset);
                    }
                }
                var temp = Vec3.zero();
                function copy3t(t, src, tar, add) {
                    var v = temp;
                    for (var i = 0, __i = src.length; i < __i; i += 3) {
                        v[0] = src[i], v[1] = src[i + 1], v[2] = src[i + 2];
                        Vec3.transformMat4(v, v, t);
                        add(tar, v[0], v[1], v[2]);
                    }
                }
                function copy2o(offset, src, tar, add) {
                    for (var i = 0, __i = src.length; i < __i; i += 2) {
                        add(tar, src[i] + offset, src[i + 1] + offset);
                    }
                }
                function error(msg) {
                    throw new Error(msg);
                }
                var scaleTransform = Mat4.zero(), translateTransform = Mat4.zero(), rotateTransform = Mat4.zero(), vTransform = Mat4.zero(), nTransform = Mat4.zero();
                var defaulScale = Vec3.fromValues(1, 1, 1), defaultTranslation = Vec3.zero();
                function addRawTransformed(builder, geom, scale, translation, rotation) {
                    Mat4.fromScaling(scaleTransform, scale || defaulScale);
                    Mat4.fromTranslation(translateTransform, translation || defaultTranslation);
                    if (rotation)
                        Mat4.copy(rotateTransform, rotation);
                    else
                        Mat4.fromIdentity(rotateTransform);
                    Mat4.mul3(vTransform, translateTransform, rotateTransform, scaleTransform);
                    var offset = builder.vertices.elementCount;
                    var addV = builder.type === 'Static' ? add3s : add3d;
                    copy3t(vTransform, geom.vertices, builder.vertices, addV);
                    if (builder.normals) {
                        if (!geom.normals)
                            error('geom is missing normals.');
                        Mat4.mul(nTransform, rotateTransform, scaleTransform);
                        copy3t(nTransform, geom.normals, builder.normals, addV);
                    }
                    if (builder.elementSize === 2) {
                        copy2o(offset, geom.indices, builder.indices, builder.type === 'Static' ? add2s : add2d);
                    }
                    else {
                        copy3o(offset, geom.indices, builder.indices, builder.type === 'Static' ? add3s : add3d);
                    }
                }
                Builder.addRawTransformed = addRawTransformed;
                function addVertex3s(builder, x, y, z) {
                    add3s(builder.vertices, x, y, z);
                }
                Builder.addVertex3s = addVertex3s;
                function addNormal3s(builder, x, y, z) {
                    add3s(builder.normals, x, y, z);
                }
                Builder.addNormal3s = addNormal3s;
                function addIndex3s(builder, i, j, k) {
                    add3s(builder.indices, i, j, k);
                }
                Builder.addIndex3s = addIndex3s;
                function addVertex3d(builder, x, y, z) {
                    add3d(builder.vertices, x, y, z);
                }
                Builder.addVertex3d = addVertex3d;
                function addNormal3d(builder, x, y, z) {
                    add3d(builder.normals, x, y, z);
                }
                Builder.addNormal3d = addNormal3d;
                function addIndex3d(builder, i, j, k) {
                    add3d(builder.indices, i, j, k);
                }
                Builder.addIndex3d = addIndex3d;
                var dashTemplate = void 0;
                function getDashTemplate() {
                    if (dashTemplate)
                        return dashTemplate;
                    dashTemplate = Visualization.GeometryHelper.toRawGeometry(new Visualization.THREE.BoxGeometry(1, 1, 1));
                    for (var i = 0; i < dashTemplate.vertices.length; i += 3) {
                        dashTemplate.vertices[i] += 0.5;
                    }
                    return dashTemplate;
                }
                Builder.getDashTemplate = getDashTemplate;
                var dashScale = Vec3.zero(), dashOffset = Vec3.zero(), dashDir = Vec3.zero(), dashUp = Vec3.fromValues(1, 0, 0), dashRotation = Mat4.zero();
                function addDashedLine(builder, a, b, size, gap, r) {
                    var dir = Vec3.sub(dashDir, b, a);
                    var length = Vec3.magnitude(dir);
                    var scale = Vec3.set(dashScale, size, r, r);
                    var rotation = Vec3.makeRotation(dashRotation, dashUp, dir);
                    var templ = getDashTemplate();
                    var offset = dashOffset;
                    Vec3.copy(offset, a);
                    Vec3.normalize(dir, dir);
                    var delta = size + gap;
                    Vec3.scale(dir, dir, delta);
                    for (var t = 0; t < length; t += delta) {
                        if (t + size > length)
                            scale[0] = length - t;
                        addRawTransformed(builder, templ, scale, offset, rotation);
                        Vec3.add(offset, offset, dir);
                    }
                }
                Builder.addDashedLine = addDashedLine;
                function compactS(tar) {
                    return tar.array;
                }
                function compactD(tar) {
                    return ChunkedArray.compact(tar);
                }
                function toBufferGeometry(builder) {
                    var compact = builder.type === 'Static' ? compactS : compactD;
                    return Geometry.toBufferGeometry({
                        vertices: compact(builder.vertices),
                        vertexCount: builder.vertices.elementCount,
                        normals: builder.normals && compact(builder.normals),
                        indices: compact(builder.indices),
                        indexCount: builder.indices.elementCount,
                        elementSize: builder.elementSize
                    });
                }
                Builder.toBufferGeometry = toBufferGeometry;
            })(Builder = Geometry.Builder || (Geometry.Builder = {}));
        })(Geometry = Visualization.Geometry || (Visualization.Geometry = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Surface;
        (function (Surface) {
            "use strict";
            var ChunkedArray = LiteMol.Core.Utils.ChunkedArray;
            function sortAnnotation(ctx) {
                var indices = new Int32Array(ctx.data.annotation.length);
                var annotation = ctx.data.annotation;
                for (var i = 0, _b = indices.length; i < _b; i++)
                    indices[i] = i;
                Array.prototype.sort.call(indices, function (a, b) {
                    var ret = annotation[a] - annotation[b];
                    if (!ret)
                        return a - b;
                    return ret;
                });
                return indices;
            }
            function splice(start, end, indices, map) {
                var currentStart = start;
                var currentEnd = start + 1;
                while (currentStart < end) {
                    while (currentEnd < end && indices[currentEnd] - indices[currentEnd - 1] < 1.1)
                        currentEnd++;
                    map.addVertexRange(indices[currentStart], indices[currentEnd - 1] + 1);
                    currentStart = currentEnd;
                    currentEnd = currentEnd + 1;
                }
            }
            function createVertexMap(ctx) {
                var indices = sortAnnotation(ctx);
                var annotation = ctx.data.annotation;
                var count = 1;
                for (var i = 0, _b = indices.length - 1; i < _b; i++) {
                    if (annotation[indices[i]] !== annotation[indices[i + 1]])
                        count++;
                }
                var map = new Visualization.Selection.VertexMapBuilder(count);
                var xs = new Int32Array(indices.length);
                for (var i = 0, _b = indices.length; i < _b; i++) {
                    xs[i] = annotation[indices[i]];
                }
                var currentAnnotation = annotation[indices[0]];
                map.startElement(currentAnnotation);
                for (var i = 0, _b = indices.length; i < _b; i++) {
                    var an = annotation[indices[i]];
                    if (an !== currentAnnotation) {
                        map.endElement();
                        map.startElement(an);
                        currentAnnotation = an;
                    }
                    var start = i;
                    i++;
                    while (an === annotation[indices[i]])
                        i++;
                    var end = i;
                    i--;
                    splice(start, end, indices, map);
                }
                map.endElement();
                return map.getMap();
            }
            function createFullMap(ctx) {
                var map = new Visualization.Selection.VertexMapBuilder(1);
                map.startElement(0);
                map.addVertexRange(0, ctx.vertexCount);
                map.endElement();
                return map.getMap();
            }
            function computeVertexMap(ctx) {
                return __awaiter(this, void 0, void 0, function () {
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, ctx.computation.updateProgress('Computing selection map...')];
                            case 1:
                                _a.sent();
                                if (ctx.data.annotation) {
                                    ctx.geom.elementToVertexMap = createVertexMap(ctx);
                                }
                                else {
                                    ctx.geom.elementToVertexMap = createFullMap(ctx);
                                }
                                return [2 /*return*/];
                        }
                    });
                });
            }
            var chunkSize = 100000;
            function computePickPlatesChunk(start, ctx) {
                return __awaiter(this, void 0, void 0, function () {
                    var tri, ids, pickPlatesVertices, pickPlatesTris, pickPlatesColors, vs, color, pickTris, platesVertexCount, i, _b, a, b, c, aI, bI, cI, s;
                    return __generator(this, function (_a) {
                        tri = ctx.data.triangleIndices;
                        ids = ctx.data.annotation;
                        pickPlatesVertices = ctx.pickPlatesVertices;
                        pickPlatesTris = ctx.pickPlatesTris;
                        pickPlatesColors = ctx.pickPlatesColors;
                        vs = ctx.data.vertices;
                        color = { r: 0.45, g: 0.45, b: 0.45 };
                        pickTris = ctx.pickTris;
                        platesVertexCount = 0;
                        for (i = start, _b = Math.min(start + chunkSize, ctx.triCount); i < _b; i++) {
                            a = tri[3 * i], b = tri[3 * i + 1], c = tri[3 * i + 2];
                            aI = ids[a], bI = ids[b], cI = ids[c];
                            if (aI === bI && bI === cI) {
                                ChunkedArray.add3(pickTris, a, b, c);
                                continue;
                            }
                            s = -1;
                            if (aI === bI || aI === cI)
                                s = aI;
                            else if (bI === cI)
                                s = bI;
                            ChunkedArray.add3(pickPlatesVertices, vs[3 * a], vs[3 * a + 1], vs[3 * a + 2]);
                            ChunkedArray.add3(pickPlatesVertices, vs[3 * b], vs[3 * b + 1], vs[3 * b + 2]);
                            ChunkedArray.add3(pickPlatesVertices, vs[3 * c], vs[3 * c + 1], vs[3 * c + 2]);
                            ChunkedArray.add3(pickPlatesTris, platesVertexCount++, platesVertexCount++, platesVertexCount++);
                            if (s < 0) {
                                color.r = 0;
                                color.g = 0;
                                color.b = 0;
                            }
                            else {
                                Visualization.Selection.Picking.assignPickColor(s, color);
                            }
                            ChunkedArray.add4(pickPlatesColors, color.r, color.g, color.b, 0.0);
                            ChunkedArray.add4(pickPlatesColors, color.r, color.g, color.b, 0.0);
                            ChunkedArray.add4(pickPlatesColors, color.r, color.g, color.b, 0.0);
                        }
                        ctx.platesVertexCount = ctx.platesVertexCount + platesVertexCount;
                        return [2 /*return*/];
                    });
                });
            }
            function computePickPlatesChunks(ctx) {
                return __awaiter(this, void 0, void 0, function () {
                    var started, start, time;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                started = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                start = 0;
                                _a.label = 1;
                            case 1:
                                if (!(start < ctx.triCount)) return [3 /*break*/, 5];
                                time = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                if (!(time - started > LiteMol.Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 3];
                                started = time;
                                return [4 /*yield*/, ctx.computation.updateProgress('Creating selection geometry...', true, start, ctx.triCount)];
                            case 2:
                                _a.sent();
                                _a.label = 3;
                            case 3:
                                computePickPlatesChunk(start, ctx);
                                _a.label = 4;
                            case 4:
                                start += chunkSize;
                                return [3 /*break*/, 1];
                            case 5: return [2 /*return*/];
                        }
                    });
                });
            }
            function assignPickColors(ctx) {
                var color = { r: 0.45, g: 0.45, b: 0.45 }, ids = ctx.data.annotation;
                ctx.pickTris = ChunkedArray.forIndexBuffer(ctx.triCount);
                var pickColorBuffer = ctx.pickColorBuffer;
                for (var i = 0, _b = ctx.vertexCount; i < _b; i++) {
                    var id = ids[i];
                    if (id >= 0) {
                        Visualization.Selection.Picking.assignPickColor(id + 1, color);
                        pickColorBuffer[i * 4] = color.r;
                        pickColorBuffer[i * 4 + 1] = color.g;
                        pickColorBuffer[i * 4 + 2] = color.b;
                    }
                }
            }
            function createFullPickGeometry(attr, ctx) {
                var pickGeometry = new Visualization.THREE.BufferGeometry();
                pickGeometry.addAttribute('position', attr.position);
                pickGeometry.addAttribute('index', attr.index);
                pickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(ctx.pickColorBuffer, 4));
                ctx.geom.pickGeometry = pickGeometry;
                pickGeometry = new Visualization.THREE.BufferGeometry();
                pickGeometry.addAttribute('position', new Visualization.THREE.BufferAttribute(new Float32Array(0), 3));
                pickGeometry.addAttribute('index', new Visualization.THREE.BufferAttribute(new Uint32Array(0), 1));
                pickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(new Float32Array(0), 4));
                ctx.geom.pickPlatesGeometry = pickGeometry;
            }
            function createPickGeometry(attr, ctx) {
                var pickGeometry = new Visualization.THREE.BufferGeometry();
                pickGeometry.addAttribute('position', attr.position);
                pickGeometry.addAttribute('index', attr.index);
                pickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(ctx.pickColorBuffer, 4));
                ctx.geom.pickGeometry = pickGeometry;
                pickGeometry = new Visualization.THREE.BufferGeometry();
                pickGeometry.addAttribute('position', new Visualization.THREE.BufferAttribute(ChunkedArray.compact(ctx.pickPlatesVertices), 3));
                pickGeometry.addAttribute('index', new Visualization.THREE.BufferAttribute(ChunkedArray.compact(ctx.pickPlatesTris), 1));
                pickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(ChunkedArray.compact(ctx.pickPlatesColors), 4));
                ctx.geom.pickPlatesGeometry = pickGeometry;
            }
            function addWireframeEdge(edges, included, a, b) {
                if (a > b) {
                    // swap
                    var t = a;
                    a = b;
                    b = t;
                }
                if (included.add((a + b) * (a + b + 1) / 2 + b /* cantor pairing function */)) {
                    ChunkedArray.add2(edges, a, b);
                }
            }
            function buildWireframeIndices(ctx) {
                var tris = ctx.data.triangleIndices;
                var edges = ChunkedArray.create(function (size) { return new Uint32Array(size); }, (1.5 * ctx.triCount) | 0, 2);
                var includedEdges = LiteMol.Core.Utils.FastSet.create();
                for (var i = 0, _b = tris.length; i < _b; i += 3) {
                    var a = tris[i], b = tris[i + 1], c = tris[i + 2];
                    addWireframeEdge(edges, includedEdges, a, b);
                    addWireframeEdge(edges, includedEdges, a, c);
                    addWireframeEdge(edges, includedEdges, b, c);
                }
                return new Visualization.THREE.BufferAttribute(ChunkedArray.compact(edges), 1);
            }
            function makeBasicAttributes(ctx) {
                return {
                    position: new Visualization.THREE.BufferAttribute(ctx.data.vertices, 3),
                    index: new Visualization.THREE.BufferAttribute(ctx.data.triangleIndices, 1)
                };
            }
            function createGeometry(attr, isWireframe, ctx) {
                var geometry = new Visualization.THREE.BufferGeometry();
                geometry.addAttribute('position', attr.position);
                geometry.addAttribute('normal', new Visualization.THREE.BufferAttribute(ctx.data.normals, 3));
                geometry.addAttribute('color', new Visualization.THREE.BufferAttribute(new Float32Array(ctx.data.vertices.length), 3));
                if (isWireframe) {
                    geometry.addAttribute('index', buildWireframeIndices(ctx));
                }
                else {
                    geometry.addAttribute('index', attr.index);
                }
                ctx.geom.geometry = geometry;
                ctx.geom.vertexStateBuffer = new Visualization.THREE.BufferAttribute(new Float32Array(ctx.data.vertices.length), 1);
                geometry.addAttribute('vState', ctx.geom.vertexStateBuffer);
            }
            function computePickGeometry(attr, ctx) {
                return __awaiter(this, void 0, void 0, function () {
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, ctx.computation.updateProgress('Creating selection geometry...')];
                            case 1:
                                _a.sent();
                                ctx.pickColorBuffer = new Float32Array(ctx.vertexCount * 4);
                                if (!!ctx.data.annotation) return [3 /*break*/, 2];
                                createFullPickGeometry(attr, ctx);
                                return [2 /*return*/];
                            case 2:
                                assignPickColors(ctx);
                                ctx.pickPlatesVertices = ChunkedArray.forVertex3D(Math.max(ctx.vertexCount / 10, 10));
                                ctx.pickPlatesTris = ChunkedArray.forIndexBuffer(Math.max(ctx.triCount / 10, 10));
                                ctx.pickPlatesColors = ChunkedArray.create(function (s) { return new Float32Array(s); }, Math.max(ctx.vertexCount / 10, 10), 4);
                                ctx.platesVertexCount = 0;
                                return [4 /*yield*/, computePickPlatesChunks(ctx)];
                            case 3:
                                _a.sent();
                                createPickGeometry(attr, ctx);
                                _a.label = 4;
                            case 4: return [2 /*return*/];
                        }
                    });
                });
            }
            function buildGeometry(data, computation, isWireframe) {
                return __awaiter(this, void 0, void 0, function () {
                    var ctx, attr;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                ctx = {
                                    data: data,
                                    computation: computation,
                                    geom: new Geometry(),
                                    vertexCount: (data.vertices.length / 3) | 0,
                                    triCount: (data.triangleIndices.length / 3) | 0
                                };
                                return [4 /*yield*/, computation.updateProgress('Creating geometry...')];
                            case 1:
                                _a.sent();
                                return [4 /*yield*/, LiteMol.Core.Geometry.Surface.computeNormals(data).run(computation)];
                            case 2:
                                _a.sent();
                                return [4 /*yield*/, LiteMol.Core.Geometry.Surface.computeBoundingSphere(data).run(computation)];
                            case 3:
                                _a.sent();
                                attr = makeBasicAttributes(ctx);
                                return [4 /*yield*/, computeVertexMap(ctx)];
                            case 4:
                                _a.sent();
                                return [4 /*yield*/, computePickGeometry(attr, ctx)];
                            case 5:
                                _a.sent();
                                createGeometry(attr, isWireframe, ctx);
                                ctx.geom.vertexToElementMap = ctx.data.annotation;
                                return [2 /*return*/, ctx.geom];
                        }
                    });
                });
            }
            Surface.buildGeometry = buildGeometry;
            var Geometry = /** @class */ (function (_super) {
                __extends(Geometry, _super);
                function Geometry() {
                    var _this = _super.call(this) || this;
                    _this.geometry = void 0;
                    _this.vertexToElementMap = void 0;
                    _this.elementToVertexMap = void 0;
                    _this.pickGeometry = void 0;
                    _this.pickPlatesGeometry = void 0;
                    _this.vertexStateBuffer = void 0;
                    return _this;
                }
                Geometry.prototype.dispose = function () {
                    this.geometry.dispose();
                    if (this.pickGeometry) {
                        this.pickGeometry.dispose();
                        this.pickPlatesGeometry.dispose();
                    }
                };
                return Geometry;
            }(Visualization.GeometryBase));
            Surface.Geometry = Geometry;
        })(Surface = Visualization.Surface || (Visualization.Surface = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Surface;
        (function (Surface) {
            "use strict";
            Surface.DefaultSurfaceModelParameters = {
                isWireframe: false,
                mapPickElements: void 0
            };
            var Model = /** @class */ (function (_super) {
                __extends(Model, _super);
                function Model() {
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this._mapPickElements = void 0;
                    return _this;
                }
                Model.prototype.applySelectionInternal = function (indices, action) {
                    var buffer = this.geometry.vertexStateBuffer, array = buffer.array, map = this.geometry.elementToVertexMap, vertexRanges = map.vertexRanges, changed = false;
                    for (var _i = 0, indices_8 = indices; _i < indices_8.length; _i++) {
                        var index = indices_8[_i];
                        if (!map.elementMap.has(index))
                            continue;
                        var indexOffset = map.elementMap.get(index), rangeStart = map.elementRanges[2 * indexOffset], rangeEnd = map.elementRanges[2 * indexOffset + 1];
                        if (rangeStart === rangeEnd)
                            continue;
                        for (var i = rangeStart; i < rangeEnd; i += 2) {
                            var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                            changed = Visualization.Selection.applyActionToRange(array, vStart, vEnd, action) || changed;
                        }
                    }
                    if (!changed)
                        return false;
                    buffer.needsUpdate = true;
                    return true;
                };
                Model.prototype.highlightElement = function (pickId, highlight) {
                    if (this.surface.annotation) {
                        return this.applySelection([pickId - 1], highlight ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                    }
                    else {
                        return this.highlightInternal(highlight);
                    }
                };
                Model.prototype.highlightInternal = function (isOn) {
                    return Visualization.Selection.applyActionToBuffer(this.geometry.vertexStateBuffer, isOn ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                };
                Model.prototype.getPickElements = function (pickId) {
                    if (!pickId)
                        return [0];
                    if (this._mapPickElements) {
                        return this._mapPickElements(pickId - 1) || [];
                    }
                    return [pickId - 1];
                };
                Model.prototype.getBoundingSphereOfSelection = function (indices) {
                    if (!this.geometry.vertexToElementMap)
                        return { radius: this.radius, center: LiteMol.Core.Geometry.LinearAlgebra.Vector3.fromObj(this.centroid) };
                    var vs = this.geometry.geometry.attributes.position.array;
                    var center = new Visualization.THREE.Vector3(), count = 0;
                    var map = this.geometry.elementToVertexMap, vertexRanges = map.vertexRanges;
                    for (var _i = 0, indices_9 = indices; _i < indices_9.length; _i++) {
                        var index = indices_9[_i];
                        if (!map.elementMap.has(index))
                            continue;
                        var indexOffset = map.elementMap.get(index), rangeStart = map.elementRanges[2 * indexOffset], rangeEnd = map.elementRanges[2 * indexOffset + 1];
                        if (rangeStart === rangeEnd)
                            continue;
                        for (var i = rangeStart; i < rangeEnd; i += 2) {
                            var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                            for (var j = vStart; j < vEnd; j++) {
                                center.x += vs[3 * j];
                                center.y += vs[3 * j + 1];
                                center.z += vs[3 * j + 2];
                                count++;
                            }
                        }
                    }
                    if (!count)
                        return void 0;
                    center.x = center.x / count;
                    center.y = center.y / count;
                    center.z = center.z / count;
                    var t = new Visualization.THREE.Vector3();
                    var radius = 0;
                    for (var _a = 0, indices_10 = indices; _a < indices_10.length; _a++) {
                        var index = indices_10[_a];
                        if (!map.elementMap.has(index))
                            continue;
                        var indexOffset = map.elementMap.get(index), rangeStart = map.elementRanges[2 * indexOffset], rangeEnd = map.elementRanges[2 * indexOffset + 1];
                        if (rangeStart === rangeEnd)
                            continue;
                        for (var i = rangeStart; i < rangeEnd; i += 2) {
                            var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                            for (var j = vStart; j < vEnd; j++) {
                                t.x = vs[3 * j];
                                t.y = vs[3 * j + 1];
                                t.z = vs[3 * j + 2];
                                radius = Math.max(radius, t.distanceToSquared(center));
                            }
                        }
                    }
                    radius = Math.sqrt(radius);
                    return {
                        radius: radius,
                        center: LiteMol.Core.Geometry.LinearAlgebra.Vector3.fromObj(center)
                    };
                };
                Model.prototype.applyThemeInternal = function (theme) {
                    var color = { r: 0, g: 0, b: 0 };
                    Visualization.MaterialsHelper.updateMaterial(this.material, theme, this.object);
                    var colors = this.geometry.geometry.attributes.color.array, ids = this.geometry.vertexToElementMap;
                    if (ids) {
                        for (var i = 0, _b = (colors.length / 3) | 0; i < _b; i++) {
                            var id = ids[i];
                            if (id < 0) {
                                color.r = 0;
                                color.g = 0;
                                color.b = 0;
                            }
                            else {
                                theme.setElementColor(id, color);
                            }
                            colors[3 * i] = color.r;
                            colors[3 * i + 1] = color.g;
                            colors[3 * i + 2] = color.b;
                        }
                    }
                    else {
                        theme.setElementColor(0, color);
                        for (var i = 0, _b = (colors.length / 3) | 0; i < _b; i++) {
                            colors[3 * i] = color.r;
                            colors[3 * i + 1] = color.g;
                            colors[3 * i + 2] = color.b;
                        }
                    }
                    if (this.pickObject)
                        this.pickObject.visible = this.getPickObjectVisibility(this.object.visible);
                    this.geometry.geometry.getAttribute('color').needsUpdate = true;
                };
                Model.prototype.getPickObjectVisibility = function (visible) {
                    if (Visualization.Theme.isTransparent(this.theme) || !this.theme.interactive) {
                        return false;
                    }
                    else {
                        return visible;
                    }
                };
                Model.prototype.createObjects = function () {
                    var mesh = new Visualization.THREE.Mesh(this.geometry.geometry, this.material);
                    var pickObj = void 0;
                    if (this.geometry.pickGeometry) {
                        pickObj = new Visualization.THREE.Object3D();
                        var pick = new Visualization.THREE.Mesh(this.geometry.pickGeometry, this.pickMaterial);
                        pickObj.add(pick);
                        pick = new Visualization.THREE.Mesh(this.geometry.pickPlatesGeometry, this.pickMaterial);
                        pickObj.add(pick);
                    }
                    return {
                        main: mesh,
                        pick: pickObj
                    };
                };
                Model.create = function (entity, _a) {
                    var _this = this;
                    var surface = _a.surface, theme = _a.theme, _c = _a.parameters, parameters = _c === void 0 ? Surface.DefaultSurfaceModelParameters : _c, props = _a.props;
                    return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var geometry, ret, center, obj;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, Surface.buildGeometry(surface, ctx, !!parameters.isWireframe)];
                                case 1:
                                    geometry = _a.sent();
                                    ret = new Model();
                                    ret._mapPickElements = parameters.mapPickElements;
                                    ret.surface = surface;
                                    ret.material = Visualization.MaterialsHelper.getMeshMaterial(Visualization.THREE.FlatShading, !!parameters.isWireframe); //new THREE.MeshPhongMaterial({ specular: 0xAAAAAA, /*ambient: 0xffffff, */shininess: 1, shading: THREE.FlatShading, side: THREE.DoubleSide, vertexColors: THREE.VertexColors });
                                    ret.geometry = geometry;
                                    ret.pickMaterial = Visualization.MaterialsHelper.getPickMaterial();
                                    ret.entity = entity;
                                    center = surface.boundingSphere.center;
                                    ret.centroid = new Visualization.THREE.Vector3(center[0], center[1], center[2]);
                                    ret.radius = surface.boundingSphere.radius;
                                    if (props)
                                        ret.props = props;
                                    ret.disposeList.push(ret.geometry, ret.material, ret.pickMaterial);
                                    obj = ret.createObjects();
                                    ret.object = obj.main;
                                    ret.pickObject = obj.pick;
                                    ret.applyTheme(theme);
                                    ret.pickBufferAttributes = [ret.geometry.pickGeometry.attributes.pColor, ret.geometry.pickPlatesGeometry.attributes.pColor];
                                    return [2 /*return*/, ret];
                            }
                        });
                    }); });
                };
                return Model;
            }(Visualization.Model));
            Surface.Model = Model;
        })(Surface = Visualization.Surface || (Visualization.Surface = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Lines;
        (function (Lines) {
            "use strict";
            var Geometry = /** @class */ (function (_super) {
                __extends(Geometry, _super);
                function Geometry() {
                    var _this = _super.call(this) || this;
                    _this.geometry = void 0;
                    _this.center = new Visualization.THREE.Vector3(0, 0, 0);
                    _this.radius = 0;
                    return _this;
                }
                Geometry.prototype.dispose = function () {
                    this.geometry.dispose();
                };
                Geometry.create = function (vertices, indices) {
                    var ret = new Geometry();
                    var center = new Visualization.THREE.Vector3(0, 0, 0);
                    for (var i = 0, _b = vertices.length; i < _b; i += 3) {
                        center.x += vertices[i];
                        center.y += vertices[i + 1];
                        center.z += vertices[i + 2];
                    }
                    center.multiplyScalar(1 / (vertices.length / 3));
                    var radius = 0;
                    for (var i = 0, _b = vertices.length; i < _b; i += 3) {
                        var dx = center.x - vertices[i];
                        var dy = center.y - vertices[i + 1];
                        var dz = center.z - vertices[i + 2];
                        var d = dx * dx + dy * dy + dz * dz;
                        if (d > radius)
                            radius = d;
                    }
                    radius = Math.sqrt(radius);
                    var geometry = new Visualization.THREE.BufferGeometry();
                    geometry.addAttribute('position', new Visualization.THREE.BufferAttribute(vertices, 3));
                    geometry.addAttribute('index', new Visualization.THREE.BufferAttribute(indices, 1));
                    ret.geometry = geometry;
                    ret.center = center;
                    ret.radius = radius;
                    return ret;
                };
                return Geometry;
            }(Visualization.GeometryBase));
            Lines.Geometry = Geometry;
        })(Lines = Visualization.Lines || (Visualization.Lines = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Lines;
        (function (Lines) {
            "use strict";
            var Model = /** @class */ (function (_super) {
                __extends(Model, _super);
                function Model() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Model.prototype.applySelectionInternal = function (indices, action) {
                    return false;
                };
                Model.prototype.highlightElement = function (pickId, highlight) {
                    return this.applySelection([pickId], highlight ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                };
                Model.prototype.highlightInternal = function (isOn) {
                    return false;
                };
                Model.prototype.getPickElements = function (pickId) {
                    return [pickId];
                };
                Model.prototype.applyThemeInternal = function (theme) {
                    var color = theme.colors.get('Uniform');
                    this.material.color = new Visualization.THREE.Color(color.r, color.g, color.b);
                    this.material.needsUpdate = true;
                };
                Model.prototype.getPickObjectVisibility = function (visible) {
                    return false;
                };
                Model.prototype.createObjects = function () {
                    return {
                        main: new Visualization.THREE.Mesh(this.geometry.geometry, this.material),
                        pick: void 0
                    };
                };
                Model.create = function (entity, _a) {
                    var _this = this;
                    var geometry = _a.geometry, theme = _a.theme, props = _a.props;
                    return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var ret, obj;
                        return __generator(this, function (_a) {
                            ret = new Model();
                            ret.material = new Visualization.THREE.MeshBasicMaterial({ wireframe: true });
                            ret.geometry = geometry;
                            ret.entity = entity;
                            ret.centroid = geometry.center;
                            ret.radius = geometry.radius;
                            if (props)
                                ret.props = props;
                            ret.disposeList.push(ret.geometry, ret.material);
                            obj = ret.createObjects();
                            ret.object = obj.main;
                            ret.pickObject = void 0;
                            ret.applyTheme(theme);
                            ret.pickBufferAttributes = [];
                            return [2 /*return*/, ret];
                        });
                    }); });
                };
                return Model;
            }(Visualization.Model));
            Lines.Model = Model;
        })(Lines = Visualization.Lines || (Visualization.Lines = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Labels;
        (function (Labels) {
            'use strict';
            Labels.DefaultTextAtlasParams = {
                font: ['sans-serif'],
                size: 36,
                style: 'normal',
                variant: 'normal',
                weight: 'normal',
                outline: 0,
                width: 2048,
                height: 2048
            };
            var TextAtlasCache = LiteMol.Core.Utils.FastMap.create();
            function getTextAtlas(params) {
                var hash = JSON.stringify(params);
                if (TextAtlasCache.has(hash))
                    return TextAtlasCache.get(hash);
                var atlas = new TextAtlas(params);
                TextAtlasCache.set(hash, atlas);
                return atlas;
            }
            Labels.getTextAtlas = getTextAtlas;
            var TextAtlas = /** @class */ (function () {
                function TextAtlas(params) {
                    this.gamma = 1;
                    this.mapped = LiteMol.Core.Utils.FastMap.create();
                    this.state = { scratchW: 0, scratchH: 0, currentX: 0, currentY: 0 };
                    this.lineHeight = 0;
                    this.params = LiteMol.Core.Utils.extend({}, params, Labels.DefaultTextAtlasParams);
                    if (typeof navigator !== 'undefined') {
                        var ua = navigator.userAgent;
                        if (ua.match(/Chrome/) && ua.match(/OS X/)) {
                            this.gamma = 0.5;
                        }
                    }
                    this.build();
                    this.populate();
                    this.texture = new Visualization.THREE.Texture(this.canvas.canvas2);
                    this.texture.flipY = false;
                    this.texture.needsUpdate = true;
                    // no need to hold the reference.
                    this.canvas = void 0;
                }
                TextAtlas.prototype.build = function () {
                    var params = this.params;
                    // Prepare line-height with room for outline and descenders/ascenders
                    var lineHeight = params.size + 2 * params.outline + Math.round(params.size / 4);
                    var maxWidth = params.width / 4;
                    // Prepare scratch canvas
                    var canvas = document.createElement("canvas");
                    canvas.width = maxWidth;
                    canvas.height = lineHeight;
                    var ctx = canvas.getContext("2d");
                    ctx.font = params.style + " " + params.variant + " " + params.weight + " " + params.size + "px " + params.font;
                    ctx.fillStyle = "#FF0000";
                    ctx.textAlign = "left";
                    ctx.textBaseline = "bottom";
                    ctx.lineJoin = "round";
                    var colors = [];
                    var dilate = params.outline * 3;
                    for (var i = 0; i < dilate; ++i) {
                        // 8 rgb levels = 1 step = .5 pixel increase
                        var val = Math.max(0, -i * 8 + 128 - (+(!i)) * 8);
                        var hex = ("00" + val.toString(16)).slice(-2);
                        colors.push("#" + hex + hex + hex);
                    }
                    var scratch = new Uint8Array(maxWidth * lineHeight * 2);
                    var data = new Uint8Array(params.width * params.height * 4);
                    var canvas2 = document.createElement('canvas');
                    canvas2.width = params.width;
                    canvas2.height = params.height;
                    var ctx2 = canvas2.getContext('2d');
                    this.canvas = {
                        canvas: canvas, ctx: ctx,
                        canvas2: canvas2, ctx2: ctx2,
                        maxWidth: maxWidth,
                        colors: colors,
                        scratch: scratch,
                        data: data
                    };
                    this.lineHeight = lineHeight;
                };
                TextAtlas.prototype.map = function (text) {
                    if (this.mapped.has(text))
                        return this.mapped.get(text);
                    this.draw(text);
                    var state = this.state;
                    if (state.currentX + state.scratchW > this.params.width) {
                        state.currentX = 0;
                        state.currentY += state.scratchH;
                    }
                    if (state.currentY + state.scratchH > this.params.height) {
                        console.warn("TextAtlas canvas to small");
                    }
                    var metrics = {
                        x: state.currentX,
                        y: state.currentY,
                        w: state.scratchW,
                        h: state.scratchH
                    };
                    this.mapped.set(text, metrics);
                    this.canvas.ctx2.drawImage(this.canvas.canvas, 0, 0, state.scratchW, state.scratchH, state.currentX, state.currentY, state.scratchW, state.scratchH);
                    state.currentX += state.scratchW;
                    return metrics;
                };
                TextAtlas.prototype.getTextMetrics = function (text) {
                    return this.mapped.has(text) ? this.mapped.get(text) : this.placeholder;
                };
                TextAtlas.prototype.draw = function (text) {
                    var _a = this, params = _a.params, canvas = _a.canvas;
                    var h = this.lineHeight;
                    var o = params.outline;
                    var ctx = canvas.ctx;
                    var dst = canvas.scratch;
                    var max = canvas.maxWidth;
                    var colors = canvas.colors;
                    // Bottom aligned, take outline into account
                    var x = o;
                    var y = h - params.outline;
                    // Measure text
                    var m = ctx.measureText(text);
                    var w = Math.min(max, Math.ceil(m.width + 2 * x + 1));
                    // Clear scratch area
                    ctx.clearRect(0, 0, w, h);
                    var i, il, j, imageData, data;
                    if (params.outline === 0) {
                        ctx.fillText(text, x, y);
                        imageData = ctx.getImageData(0, 0, w, h);
                        data = imageData.data;
                        j = 3; // Skip to alpha channel
                        for (i = 0, il = data.length / 4; i < il; ++i) {
                            dst[i] = data[j];
                            j += 4;
                        }
                    }
                    else {
                        ctx.globalCompositeOperation = "source-over";
                        // Draw strokes of decreasing width to create
                        // nested outlines (absolute distance)
                        for (i = o + 1; i > 0; --i) {
                            // Eliminate odd strokes once past > 1px,
                            // don't need the detail
                            j = i > 1 ? i * 2 - 2 : i;
                            ctx.strokeStyle = colors[j - 1];
                            ctx.lineWidth = j;
                            ctx.strokeText(text, x, y);
                        }
                        ctx.globalCompositeOperation = "multiply";
                        ctx.fillStyle = "#FF00FF";
                        ctx.fillText(text, x, y);
                        imageData = ctx.getImageData(0, 0, w, h);
                        data = imageData.data;
                        j = 0;
                        var gamma = this.gamma;
                        for (i = 0, il = data.length / 4; i < il; ++i) {
                            // Get value + mask
                            var a = data[j];
                            var mask = a ? data[j + 1] / a : 1;
                            if (gamma === 0.5) {
                                mask = Math.sqrt(mask);
                            }
                            mask = Math.min(1, Math.max(0, mask));
                            // Blend between positive/outside and negative/inside
                            var b = 256 - a;
                            var c = b + (a - b) * mask;
                            // Clamp (slight expansion to hide errors around the transition)
                            dst[i] = Math.max(0, Math.min(255, c + 2));
                            data[j + 3] = dst[i];
                            j += 4;
                        }
                    }
                    ctx.putImageData(imageData, 0, 0);
                    this.state.scratchW = w;
                    this.state.scratchH = h;
                };
                TextAtlas.prototype.populate = function () {
                    // Replacement Character
                    this.placeholder = this.map(String.fromCharCode(0xFFFD));
                    // Basic Latin
                    for (var i = 0x0000; i < 0x007F; ++i) {
                        this.map(String.fromCharCode(i));
                    }
                    // Latin-1 Supplement
                    for (var i = 0x0080; i < 0x00FF; ++i) {
                        this.map(String.fromCharCode(i));
                    }
                    // Greek and Coptic
                    for (var i = 0x0370; i < 0x03FF; ++i) {
                        this.map(String.fromCharCode(i));
                    }
                    // Cyrillic
                    for (var i = 0x0400; i < 0x04FF; ++i) {
                        this.map(String.fromCharCode(i));
                    }
                    // Angstrom Sign
                    this.map(String.fromCharCode(0x212B));
                };
                return TextAtlas;
            }());
            Labels.TextAtlas = TextAtlas;
        })(Labels = Visualization.Labels || (Visualization.Labels = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Labels;
        (function (Labels) {
            var Geometry;
            (function (Geometry) {
                'use strict';
                /**
                 * Adapted from https://github.com/arose/ngl
                 * MIT License Copyright (C) 2014+ Alexander Rose
                 */
                function create(params) {
                    var state = initState(params);
                    calcVertices(state);
                    makeMapping(state);
                    var idx = makeIndexBuffer(state);
                    var geometry = new Visualization.THREE.BufferGeometry();
                    geometry.addAttribute('position', new Visualization.THREE.BufferAttribute(state.vertices, 3));
                    geometry.addAttribute('index', new Visualization.THREE.BufferAttribute(idx, 1));
                    geometry.addAttribute('color', new Visualization.THREE.BufferAttribute(new Float32Array(state.quadCount * 4 * 3), 3));
                    geometry.addAttribute('mapping', new Visualization.THREE.BufferAttribute(state.mapping, 2));
                    geometry.addAttribute('inputTexCoord', new Visualization.THREE.BufferAttribute(state.texCoords, 2));
                    geometry.addAttribute('inputSize', new Visualization.THREE.BufferAttribute(state.size, 1));
                    return { geometry: geometry, texture: state.textAtlas.texture, options: state.options };
                }
                Geometry.create = create;
                function initState(params) {
                    var options = LiteMol.Core.Utils.extend({}, params.options, Labels.DefaultLabelsOptions);
                    var charCount = 0;
                    for (var _i = 0, _a = params.labels; _i < _a.length; _i++) {
                        var t = _a[_i];
                        charCount += t.length;
                    }
                    var textAtlas = Labels.getTextAtlas({
                        font: [options.fontFamily],
                        style: options.fontStyle,
                        weight: options.fontWeight,
                        size: options.fontSize,
                        outline: options.useSDF ? 5 : 0
                    });
                    var quadCount = charCount + params.labels.length /* bg */;
                    return {
                        positions: params.positions,
                        inputSizes: params.sizes,
                        labels: params.labels,
                        options: options,
                        textAtlas: textAtlas,
                        charCount: charCount,
                        quadCount: quadCount,
                        vertices: new Float32Array(quadCount * 4 * 3),
                        size: new Float32Array(quadCount * 4),
                        texCoords: new Float32Array(quadCount * 4 * 2),
                        mapping: new Float32Array(quadCount * 4 * 2)
                    };
                }
                function calcVertices(state) {
                    var text = state.labels;
                    var _a = state.positions, x = _a.x, y = _a.y, z = _a.z;
                    var vertices = state.vertices, size = state.size, inputSizes = state.inputSizes;
                    var iCharAll = 0;
                    for (var v = 0; v < text.length; ++v) {
                        var txt = text[v];
                        var nChar = txt.length + 1 /* bg */;
                        for (var iChar = 0; iChar < nChar; ++iChar, ++iCharAll) {
                            for (var m = 0; m < 4; m++) {
                                var j = iCharAll * 4 * 3 + (3 * m);
                                vertices[j] = x[v];
                                vertices[j + 1] = y[v];
                                vertices[j + 2] = z[v];
                                size[iCharAll * 4 + m] = inputSizes[v];
                            }
                        }
                    }
                }
                function makeMapping(state) {
                    var ta = state.textAtlas;
                    var text = state.labels;
                    var attachment = state.options.attachment;
                    var outline = ta.params.outline, lineHeight = ta.lineHeight;
                    var margin = (ta.lineHeight * state.options.backgroundMargin * 0.1) - 10;
                    var inputTexCoord = state.texCoords;
                    var inputMapping = state.mapping;
                    var iCharAll = 0;
                    var c, i, txt, xadvance, iChar, nChar, xShift, yShift;
                    for (var v = 0; v < text.length; ++v) {
                        txt = text[v];
                        xadvance = 0;
                        nChar = txt.length;
                        // calculate width
                        for (iChar = 0; iChar < nChar; ++iChar) {
                            c = ta.getTextMetrics(txt[iChar]);
                            xadvance += c.w - 2 * outline;
                        }
                        // attachment
                        if (attachment.indexOf("top") === 0) {
                            yShift = ta.lineHeight / 1.25;
                        }
                        else if (attachment.indexOf("middle") === 0) {
                            yShift = ta.lineHeight / 2.5;
                        }
                        else {
                            yShift = 0; // "bottom"
                        }
                        if (attachment.indexOf("right") > 0) {
                            xShift = xadvance;
                        }
                        else if (attachment.indexOf("center") > 0) {
                            xShift = xadvance / 2;
                        }
                        else {
                            xShift = 0; // "left"
                        }
                        xShift += outline;
                        yShift += outline;
                        // background            
                        i = iCharAll * 2 * 4;
                        inputMapping[i + 0] = -lineHeight / 6 - xShift - margin; // top left
                        inputMapping[i + 1] = lineHeight - yShift + margin;
                        inputMapping[i + 2] = -lineHeight / 6 - xShift - margin; // bottom left
                        inputMapping[i + 3] = 0 - 1.2 * yShift - margin;
                        inputMapping[i + 4] = xadvance + lineHeight / 6 - xShift + 2 * outline + margin; // top right
                        inputMapping[i + 5] = lineHeight - yShift + margin;
                        inputMapping[i + 6] = xadvance + lineHeight / 6 - xShift + 2 * outline + margin; // bottom right
                        inputMapping[i + 7] = 0 - 1.2 * yShift - margin;
                        inputTexCoord[i + 0] = 10;
                        inputTexCoord[i + 2] = 10;
                        inputTexCoord[i + 4] = 10;
                        inputTexCoord[i + 6] = 10;
                        iCharAll += 1;
                        xadvance = 0;
                        for (iChar = 0; iChar < nChar; ++iChar, ++iCharAll) {
                            c = ta.getTextMetrics(txt[iChar]);
                            i = iCharAll * 2 * 4;
                            inputMapping[i + 0] = xadvance - xShift; // top left
                            inputMapping[i + 1] = c.h - yShift;
                            inputMapping[i + 2] = xadvance - xShift; // bottom left
                            inputMapping[i + 3] = 0 - yShift;
                            inputMapping[i + 4] = xadvance + c.w - xShift; // top right
                            inputMapping[i + 5] = c.h - yShift;
                            inputMapping[i + 6] = xadvance + c.w - xShift; // bottom right
                            inputMapping[i + 7] = 0 - yShift;
                            var texWidth = ta.params.width;
                            var texHeight = ta.params.height;
                            inputTexCoord[i + 0] = c.x / texWidth; // top left
                            inputTexCoord[i + 1] = c.y / texHeight;
                            inputTexCoord[i + 2] = c.x / texWidth; // bottom left
                            inputTexCoord[i + 3] = (c.y + c.h) / texHeight;
                            inputTexCoord[i + 4] = (c.x + c.w) / texWidth; // top right
                            inputTexCoord[i + 5] = c.y / texHeight;
                            inputTexCoord[i + 6] = (c.x + c.w) / texWidth; // bottom right
                            inputTexCoord[i + 7] = (c.y + c.h) / texHeight;
                            xadvance += c.w - 2 * outline;
                        }
                    }
                }
                function makeIndexBuffer(state) {
                    var buffer = new Uint32Array(state.quadCount * 2 * 3);
                    var o = 0;
                    for (var i = 0; i < state.quadCount; i++) {
                        buffer[o++] = 4 * i;
                        buffer[o++] = 4 * i + 1;
                        buffer[o++] = 4 * i + 2;
                        buffer[o++] = 4 * i + 1;
                        buffer[o++] = 4 * i + 3;
                        buffer[o++] = 4 * i + 2;
                    }
                    return buffer;
                }
            })(Geometry = Labels.Geometry || (Labels.Geometry = {}));
        })(Labels = Visualization.Labels || (Visualization.Labels = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Labels;
        (function (Labels) {
            var Material;
            (function (Material) {
                /**
                 * Adapted from https://github.com/arose/ngl
                 * MIT License Copyright (C) 2014+ Alexander Rose
                 */
                Material.VERTEX_SHADER = "\nuniform float xOffset;\nuniform float yOffset;\nuniform float zOffset;\nuniform float sizeFactor;\n\nvarying vec2 texCoord;\n\nattribute vec2 mapping;\nattribute vec2 inputTexCoord;\nattribute float inputSize;\n\n" + Visualization.THREE.ShaderChunk["color_pars_vertex"] + "\n" + Visualization.THREE.ShaderChunk["common"] + "\n\nfloat matrixScale( in mat4 m ){\n    vec4 r = m[ 0 ];\n    return sqrt( r[ 0 ] * r[ 0 ] + r[ 1 ] * r[ 1 ] + r[ 2 ] * r[ 2 ] );\n}\n\nvoid main(void){\n\n    " + Visualization.THREE.ShaderChunk["color_vertex"] + "\n\n    texCoord = inputTexCoord;\n\n    float scale = matrixScale( modelViewMatrix );\n\n    float _zOffset = zOffset * scale;\n    if( texCoord.x == 10.0 ){\n         _zOffset -= 0.001;\n    }\n\n    vec3 pos = position;\n    vec4 cameraPos = modelViewMatrix * vec4( pos, 1.0 );\n    vec4 cameraCornerPos = vec4( cameraPos.xyz, 1.0 );\n    cameraCornerPos.xy += mapping * inputSize * sizeFactor * 0.01 * scale;\n    cameraCornerPos.x += xOffset * scale;\n    cameraCornerPos.y += yOffset * scale;\n    cameraCornerPos.xyz += normalize( -cameraCornerPos.xyz ) * _zOffset;\n\n    gl_Position = projectionMatrix * cameraCornerPos;\n    //gl_Position.xyz = position.xyz;\n}\n";
                Material.FRAGMENT_SHADER = "\n#extension GL_OES_standard_derivatives : enable\n\nuniform sampler2D fontTexture;\nuniform vec3 outlineColor;\nuniform float outlineWidth;\nuniform vec3 backgroundColor;\nuniform float backgroundOpacity;\n\nvarying vec2 texCoord;\n\n" + Visualization.THREE.ShaderChunk["common"] + "\n" + Visualization.THREE.ShaderChunk["color_pars_fragment"] + "\n" + Visualization.THREE.ShaderChunk["fog_pars_fragment"] + "\n\nconst float smoothness = 16.0;\nconst float gamma = 2.2;\n\nvoid main(){\n    vec4 finalColor;\n\n    if( texCoord.x > 1.0 ){\n        if (backgroundOpacity < 0.05) discard;\n        finalColor = vec4( backgroundColor, backgroundOpacity );\n    }else{\n        // retrieve signed distance\n        float sdf = texture2D( fontTexture, texCoord ).a + outlineWidth;\n\n        // perform adaptive anti-aliasing of the edges\n        float w = clamp(\n            smoothness * ( abs( dFdx( texCoord.x ) ) + abs( dFdy( texCoord.y ) ) ),\n            0.0,\n            0.5\n        );\n        float a = smoothstep( 0.5 - w, 0.5 + w, sdf );\n\n        // gamma correction for linear attenuation\n        a = pow( a, 1.0 / gamma );\n        if( a < 0.2 ) discard;\n        //a *= opacity;\n\n        vec3 outgoingLight = vColor;\n        if( outlineWidth > 0.0 && sdf < ( 0.5 + outlineWidth ) ){\n            outgoingLight = outlineColor;\n        }\n\n        finalColor = vec4( outgoingLight, a );    \n    }\n\n    //gl_FragColor = finalColor;\n    vec3 outgoingLight = finalColor.rgb;\n\n    " + Visualization.THREE.ShaderChunk["fog_fragment"] + "\n    \n    #ifdef USE_FOG\n       float alpha = (1.0 - fogFactor) * finalColor.a;\n       if (alpha < 0.05) discard;\n       gl_FragColor = vec4( outgoingLight.rgb, alpha );\n    #else\n      gl_FragColor = finalColor;\n    #endif\n}\n";
            })(Material = Labels.Material || (Labels.Material = {}));
        })(Labels = Visualization.Labels || (Visualization.Labels = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Labels;
        (function (Labels) {
            var Material;
            (function (Material) {
                'use strict';
                function create(texture) {
                    var uniforms = Visualization.THREE.UniformsUtils.merge([
                        Visualization.THREE.UniformsLib["common"],
                        Visualization.THREE.UniformsLib["fog"],
                        {
                            "fontTexture": { type: "t", value: texture },
                            "xOffset": { type: "f", value: 0 },
                            "yOffset": { type: "f", value: 0 },
                            "zOffset": { type: "f", value: 0 },
                            "sizeFactor": { type: "f", value: 1.0 },
                            "outlineWidth": { type: "f", value: 0.0 },
                            "outlineColor": { type: "v3", value: new Visualization.THREE.Vector3(0, 0, 0) },
                            "backgroundColor": { type: "v3", value: new Visualization.THREE.Vector3(0, 0, 0) },
                            "backgroundOpacity": { type: "f", value: 0.5 },
                        }
                    ]);
                    uniforms.fontTexture.value = texture;
                    var ret = new Visualization.THREE.ShaderMaterial({
                        uniforms: uniforms,
                        attributes: {
                            "mapping": { type: 'v2', value: null },
                            "inputTexCoord": { type: 'v2', value: null },
                            "inputSize": { type: 'f', value: null }
                        },
                        lights: false,
                        fog: true,
                        vertexShader: Material.VERTEX_SHADER,
                        fragmentShader: Material.FRAGMENT_SHADER,
                        shading: Visualization.THREE.NoShading,
                        side: Visualization.THREE.DoubleSide,
                        vertexColors: Visualization.THREE.VertexColors,
                        blending: Visualization.THREE.NormalBlending,
                        transparent: false,
                        wireframe: false,
                        linewidth: 1
                    });
                    return ret;
                }
                Material.create = create;
            })(Material = Labels.Material || (Labels.Material = {}));
        })(Labels = Visualization.Labels || (Visualization.Labels = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Labels;
        (function (Labels) {
            'use strict';
            Labels.DefaultLabelsOptions = {
                fontFamily: 'sans-serif',
                fontSize: 32,
                fontStyle: 'normal',
                fontWeight: 'normal',
                useSDF: true,
                attachment: 'middle-center',
                backgroundMargin: 1.0
            };
            var Model = /** @class */ (function (_super) {
                __extends(Model, _super);
                function Model() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                //private options: LabelsOptions;
                Model.prototype.applySelectionInternal = function (indices, action) { return false; };
                Model.prototype.getPickElements = function (pickId) { return []; };
                ;
                Model.prototype.highlightElement = function (pickId, highlight) { return false; };
                Model.prototype.highlightInternal = function (isOn) { return false; };
                Model.prototype.applyColoring = function (theme) {
                    var color = this.geometry.attributes.color.array;
                    var o = 0, t = { r: 0.1, g: 0.1, b: 0.1 };
                    var i = 0;
                    for (var _i = 0, _a = this.labels; _i < _a.length; _i++) {
                        var l = _a[_i];
                        var count = l.length * 4 + 4 /* background */;
                        theme.setElementColor(i, t);
                        for (var j = 0; j < count; j++) {
                            color[o++] = t.r;
                            color[o++] = t.g;
                            color[o++] = t.b;
                        }
                        i++;
                    }
                    this.geometry.attributes.color.needsUpdate = true;
                };
                Model.prototype.applyThemeInternal = function (theme) {
                    this.applyColoring(theme);
                    var backgroundColor = theme.colors.get('Background') || Visualization.Color.fromHexString('#333333');
                    var backgroundOpacity = theme.variables.get('backgroundOpacity') !== void 0 ? theme.variables.get('backgroundOpacity') : 0.5;
                    var outlineColor = theme.colors.get('Outline') || Visualization.Color.fromHexString('#222222');
                    var outlineWidth = theme.variables.get('outlineWidth') ? +theme.variables.get('outlineWidth') : 0.0;
                    var sizeFactor = theme.variables.get('sizeFactor') ? +theme.variables.get('sizeFactor') : 1.0;
                    var uniforms = this.material.uniforms;
                    uniforms.xOffset.value = theme.variables.get('xOffset') || 0;
                    uniforms.yOffset.value = theme.variables.get('yOffset') || 0;
                    uniforms.zOffset.value = theme.variables.get('zOffset') || 0;
                    uniforms.backgroundColor.value = new Visualization.THREE.Vector3(backgroundColor.r, backgroundColor.g, backgroundColor.b);
                    uniforms.backgroundOpacity.value = backgroundOpacity;
                    uniforms.outlineColor.value = new Visualization.THREE.Vector3(outlineColor.r, outlineColor.g, outlineColor.b);
                    uniforms.outlineWidth.value = outlineWidth;
                    uniforms.sizeFactor.value = sizeFactor;
                    this.material.transparent = backgroundOpacity < 1.0,
                        this.material.fog = !theme.disableFog;
                    this.material.needsUpdate = true;
                };
                Model.create = function (entity, params) {
                    var _this = this;
                    return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var _a, geometry, texture /*, options*/, model;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0: return [4 /*yield*/, ctx.updateProgress('Creating labels geometry...')];
                                case 1:
                                    _b.sent();
                                    _a = Labels.Geometry.create(params), geometry = _a.geometry, texture = _a.texture;
                                    return [4 /*yield*/, ctx.updateProgress('Creating labels model...')];
                                case 2:
                                    _b.sent();
                                    model = new Model();
                                    //model.options = options;
                                    model.labels = params.labels;
                                    model.geometry = geometry;
                                    model.material = Labels.Material.create(texture);
                                    model.entity = entity;
                                    model.object = new Visualization.THREE.Mesh(geometry, model.material);
                                    model.object.renderOrder = 1;
                                    geometry.computeBoundingSphere();
                                    model.centroid = geometry.boundingSphere.center;
                                    model.radius = geometry.boundingSphere.radius + 4;
                                    model.applyTheme(params.theme);
                                    model.disposeList = [geometry, model.material];
                                    return [2 /*return*/, model];
                            }
                        });
                    }); });
                };
                return Model;
            }(Visualization.Model));
            Labels.Model = Model;
        })(Labels = Visualization.Labels || (Visualization.Labels = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var BallsAndSticks;
            (function (BallsAndSticks) {
                "use strict";
                BallsAndSticks.DefaultBallsAndSticksModelParameters = {
                    tessalation: 3,
                    atomRadius: function () { return 0.4; },
                    hideBonds: false,
                    hideHydrogens: false,
                    bondRadius: 0.15,
                    customMaxBondLengths: void 0
                };
                var Model = /** @class */ (function (_super) {
                    __extends(Model, _super);
                    function Model() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Model.prototype.applySelectionInternal = function (indices, action) {
                        var buffer = this.ballsAndSticks.vertexStateBuffer, array = buffer.array, map = this.ballsAndSticks.atomVertexMap, vertexRanges = map.vertexRanges, changed = false;
                        for (var _i = 0, indices_11 = indices; _i < indices_11.length; _i++) {
                            var index = indices_11[_i];
                            if (!map.elementMap.has(index))
                                continue;
                            var indexOffset = map.elementMap.get(index), rangeStart = map.elementRanges[2 * indexOffset], rangeEnd = map.elementRanges[2 * indexOffset + 1];
                            if (rangeStart === rangeEnd)
                                continue;
                            for (var i = rangeStart; i < rangeEnd; i += 2) {
                                var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                                changed = Visualization.Selection.applyActionToRange(array, vStart, vEnd, action) || changed;
                            }
                        }
                        if (!changed)
                            return false;
                        buffer.needsUpdate = true;
                        return true;
                    };
                    Model.prototype.getPickElements = function (pickId) {
                        return [pickId];
                    };
                    Model.prototype.highlightElement = function (pickId, highlight) {
                        return this.applySelection([pickId], highlight ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                    };
                    Model.prototype.highlightInternal = function (isOn) {
                        return Visualization.Selection.applyActionToBuffer(this.ballsAndSticks.vertexStateBuffer, isOn ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                    };
                    Model.prototype.applyThemeInternal = function (theme) {
                        var _this = this;
                        var map = this.ballsAndSticks.atomVertexMap;
                        Visualization.MaterialsHelper.applyColorToMap(map, this.ballsAndSticks.atomsGeometry.attributes.color, function (i, c) { return _this.theme.setElementColor(i, c); });
                        //map = this.ballsAndSticks.bondVertexMap;
                        var bondColor = Visualization.Theme.getColor(theme, 'Bond', Molecule.Colors.DefaultBondColor);
                        Visualization.MaterialsHelper.applyColorToBuffer(this.ballsAndSticks.bondsGeometry.attributes.color, bondColor);
                        Visualization.MaterialsHelper.updateMaterial(this.material, theme, this.object);
                        Visualization.MaterialsHelper.updateMaterial(this.bondsMaterial, theme, this.object);
                    };
                    Model.prototype.createObjects = function () {
                        var main = new Visualization.THREE.Object3D();
                        main.add(new Visualization.THREE.Mesh(this.ballsAndSticks.atomsGeometry, this.material));
                        main.add(new Visualization.THREE.Mesh(this.ballsAndSticks.bondsGeometry, this.bondsMaterial));
                        var pick = new Visualization.THREE.Mesh(this.ballsAndSticks.pickGeometry, this.pickMaterial);
                        return {
                            main: main,
                            pick: pick
                        };
                    };
                    Model.create = function (entity, _a) {
                        var _this = this;
                        var model = _a.model, atomIndices = _a.atomIndices, theme = _a.theme, params = _a.params, props = _a.props;
                        return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var geom, ret, obj;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, BallsAndSticks.buildGeometry(model, params, atomIndices, ctx)];
                                    case 1:
                                        geom = _a.sent();
                                        ret = new Model();
                                        //ret.molecule = model;
                                        ret.ballsAndSticks = geom;
                                        ret.material = Visualization.MaterialsHelper.getMeshMaterial();
                                        ret.bondsMaterial = new Visualization.THREE.MeshPhongMaterial({ specular: 0xAAAAAA, shininess: 1, shading: Visualization.THREE.SmoothShading, side: Visualization.THREE.FrontSide, vertexColors: Visualization.THREE.VertexColors });
                                        ret.pickMaterial = Visualization.MaterialsHelper.getPickMaterial();
                                        ret.entity = entity;
                                        ret.ballsAndSticks.atomsGeometry.computeBoundingSphere();
                                        ret.centroid = ret.ballsAndSticks.atomsGeometry.boundingSphere.center;
                                        ret.radius = ret.ballsAndSticks.atomsGeometry.boundingSphere.radius;
                                        if (props)
                                            ret.props = props;
                                        obj = ret.createObjects();
                                        ret.object = obj.main;
                                        ret.applyTheme(theme);
                                        ret.disposeList.push(ret.ballsAndSticks, ret.material, ret.bondsMaterial, ret.pickMaterial);
                                        ret.pickObject = obj.pick;
                                        ret.pickBufferAttributes = [ret.ballsAndSticks.pickGeometry.attributes.pColor];
                                        return [2 /*return*/, ret];
                                }
                            });
                        }); });
                    };
                    return Model;
                }(Visualization.Model));
                BallsAndSticks.Model = Model;
            })(BallsAndSticks = Molecule.BallsAndSticks || (Molecule.BallsAndSticks = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var BallsAndSticks;
            (function (BallsAndSticks) {
                "use strict";
                var Geom = LiteMol.Core.Geometry;
                var Vec3 = Geom.LinearAlgebra.Vector3;
                var Mat4 = Geom.LinearAlgebra.Matrix4;
                var GB = Visualization.Geometry.Builder;
                function isHydrogen(n) {
                    return n === 'H' || n === 'D' || n === 'T';
                }
                function getAtomCount(model, atomIndices, params) {
                    var es = model.data.atoms.elementSymbol;
                    var hideHydrogens = params.hideHydrogens;
                    var atomCount = 0;
                    if (hideHydrogens) {
                        for (var _i = 0, atomIndices_2 = atomIndices; _i < atomIndices_2.length; _i++) {
                            var aI = atomIndices_2[_i];
                            if (!isHydrogen(es[aI])) {
                                atomCount++;
                            }
                        }
                    }
                    else {
                        atomCount = atomIndices.length;
                    }
                    return atomCount;
                }
                function getBondsInfo(model, atomIndices, params) {
                    var bonds = LiteMol.Core.Structure.computeBonds(model, atomIndices, {
                        maxHbondLength: params.customMaxBondLengths && params.customMaxBondLengths.has('H') ? params.customMaxBondLengths.get('H') : 1.15
                    });
                    var metalDashFactor = 1 / (2 * 0.15 /* MetalDashSize */);
                    var es = model.data.atoms.elementSymbol;
                    var hideHydrogens = params.hideHydrogens;
                    var covalentStickCount = 0, dashPartCount = 0;
                    var type = bonds.type, count = bonds.count, atomAIndex = bonds.atomAIndex, atomBIndex = bonds.atomBIndex;
                    var _a = model.positions, x = _a.x, y = _a.y, z = _a.z;
                    for (var i = 0; i < count; i++) {
                        var t = type[i];
                        var a = atomAIndex[i], b = atomBIndex[i];
                        if (hideHydrogens && (isHydrogen(es[a]) || isHydrogen(es[b]))) {
                            continue;
                        }
                        if (t === 0 /* Unknown */ || t === 5 /* DisulfideBridge */)
                            covalentStickCount += 1;
                        else if (t >= 1 /* Single */ && t <= 4 /* Aromatic */)
                            covalentStickCount += t;
                        else if (t === 6 /* Metallic */ || t === 7 /* Ion */ || t === 8 /* Hydrogen */) {
                            var dx = x[a] - x[b], dy = y[a] - y[b], dz = z[a] - z[b];
                            var len = Math.sqrt(dx * dx + dy * dy + dz * dz);
                            dashPartCount += Math.ceil(metalDashFactor * len);
                        }
                    }
                    return {
                        bonds: bonds,
                        covalentStickCount: covalentStickCount,
                        dashPartCount: dashPartCount
                    };
                }
                var BondModelState = /** @class */ (function () {
                    function BondModelState(bondTemplate, builder) {
                        this.bondTemplate = bondTemplate;
                        this.builder = builder;
                        this.rotationAxis = Vec3.zero();
                        this.bondUpVector = Vec3.fromValues(1, 0, 0);
                        this.dir = Vec3.zero();
                        this.scale = Vec3.zero();
                        this.translation = Vec3.zero();
                        this.rotation = Mat4.zero();
                        this.offset = Vec3.zero();
                        this.a = Vec3.zero();
                        this.b = Vec3.zero();
                    }
                    return BondModelState;
                }());
                var Templates;
                (function (Templates) {
                    var bondCache = {};
                    function getBond(tessalation) {
                        if (bondCache[tessalation])
                            return bondCache[tessalation];
                        var detail;
                        switch (tessalation) {
                            case 0:
                                detail = 2;
                                break;
                            case 1:
                                detail = 4;
                                break;
                            case 2:
                                detail = 6;
                                break;
                            case 3:
                                detail = 8;
                                break;
                            case 4:
                                detail = 10;
                                break;
                            case 5:
                                detail = 12;
                                break;
                            default:
                                detail = 14;
                                break;
                        }
                        var geom = new Visualization.THREE.TubeGeometry(new Visualization.THREE.LineCurve3(new Visualization.THREE.Vector3(0, 0, 0), new Visualization.THREE.Vector3(1, 0, 0)), 2, 1.0, detail);
                        var ret = Visualization.GeometryHelper.toRawGeometry(geom);
                        bondCache[tessalation] = ret;
                        return ret;
                    }
                    Templates.getBond = getBond;
                    var atomCache = {};
                    function getAtom(tessalation) {
                        if (atomCache[tessalation])
                            return atomCache[tessalation];
                        var base, radius = 1;
                        switch (tessalation) {
                            case 0:
                                base = new Visualization.THREE.OctahedronGeometry(radius, 0);
                                break;
                            case 1:
                                base = new Visualization.THREE.OctahedronGeometry(radius, 1);
                                break;
                            case 2:
                                base = new Visualization.THREE.IcosahedronGeometry(radius, 0);
                                break;
                            case 3:
                                base = new Visualization.THREE.IcosahedronGeometry(radius, 1);
                                break;
                            case 4:
                                base = new Visualization.THREE.IcosahedronGeometry(radius, 2);
                                break;
                            case 5:
                                base = new Visualization.THREE.OctahedronGeometry(radius, 3);
                                break;
                            default:
                                base = new Visualization.THREE.IcosahedronGeometry(radius, 3);
                                break;
                        }
                        var ret = Visualization.GeometryHelper.toRawGeometry(base);
                        atomCache[tessalation] = ret;
                        return ret;
                    }
                    Templates.getAtom = getAtom;
                })(Templates || (Templates = {}));
                var BuildState = /** @class */ (function () {
                    function BuildState(model, atomIndices, params) {
                        this.model = model;
                        this.atomIndices = atomIndices;
                        this.params = params;
                        this.tessalation = this.params.tessalation;
                        this.atomRadius = this.params.atomRadius;
                        this.bondRadius = this.params.bondRadius;
                        this.hideBonds = this.params.hideBonds;
                        this.bondTemplate = Templates.getBond(this.tessalation);
                        this.atomTemplate = Templates.getAtom(this.tessalation);
                        this.dashTemplate = GB.getDashTemplate();
                        this.atomCount = getAtomCount(this.model, this.atomIndices, this.params);
                        this.atomVertexCount = this.atomTemplate.vertexCount * this.atomCount;
                        this.atomBuilder = GB.createStatic(this.atomVertexCount, this.atomTemplate.indexCount * this.atomCount);
                        this.atomColors = new Float32Array(this.atomVertexCount * 3);
                        this.atomPickColors = new Float32Array(this.atomVertexCount * 4);
                        this.atoms = this.model.data.atoms;
                        this.positions = this.model.positions;
                        this.cX = this.positions.x;
                        this.cY = this.positions.y;
                        this.cZ = this.positions.z;
                        this.atomSymbols = this.atoms.elementSymbol;
                        this.residueIndex = this.atoms.residueIndex;
                        this.scale = Vec3.zero();
                        this.translation = Vec3.zero();
                        this.pickColor = { r: 0.1, g: 0.1, b: 0.1 };
                        this.pickOffset = 0;
                        this.atomMapBuilder = new Visualization.Selection.VertexMapBuilder(this.atomIndices.length);
                        this.bs = void 0;
                    }
                    return BuildState;
                }());
                var BondsBuildState = /** @class */ (function () {
                    function BondsBuildState(state) {
                        this.state = state;
                        this.info = getBondsInfo(this.state.model, this.state.atomIndices, this.state.params);
                        this.bondVertexCount = this.state.bondTemplate.vertexCount * this.info.covalentStickCount + this.state.dashTemplate.vertexCount * this.info.dashPartCount;
                        this.bondBuilder = GB.createStatic(this.bondVertexCount, this.state.bondTemplate.indexCount * this.info.covalentStickCount + this.state.dashTemplate.indexCount * this.info.dashPartCount);
                        this.bondColors = new Float32Array(this.bondVertexCount * 3);
                        this.bondRadius = this.state.params.bondRadius;
                        this.bondState = new BondModelState(this.state.bondTemplate, this.bondBuilder);
                        this.bondCount = this.info.bonds.count;
                    }
                    return BondsBuildState;
                }());
                var BallsAndSticksGeometryBuilder = /** @class */ (function () {
                    function BallsAndSticksGeometryBuilder() {
                    }
                    BallsAndSticksGeometryBuilder.prototype.dispose = function () {
                        this.atomsGeometry.dispose();
                        this.bondsGeometry.dispose();
                        this.pickGeometry.dispose();
                    };
                    BallsAndSticksGeometryBuilder.addAtom = function (a, state) {
                        state.atomMapBuilder.startElement(a);
                        var r = state.atomRadius(a);
                        Vec3.set(state.scale, r, r, r);
                        Vec3.set(state.translation, state.cX[a], state.cY[a], state.cZ[a]);
                        var startVertexOffset = state.atomBuilder.vertices.elementCount; //!!!.vertexOffset;
                        GB.addRawTransformed(state.atomBuilder, state.atomTemplate, state.scale, state.translation, void 0);
                        Visualization.Selection.Picking.assignPickColor(a, state.pickColor);
                        for (var i = 0, _b = state.atomTemplate.vertexCount; i < _b; i++) {
                            state.atomPickColors[state.pickOffset++] = state.pickColor.r;
                            state.atomPickColors[state.pickOffset++] = state.pickColor.g;
                            state.atomPickColors[state.pickOffset++] = state.pickColor.b;
                            state.pickOffset++; // 4th component
                        }
                        state.atomMapBuilder.addVertexRange(startVertexOffset, state.atomBuilder.vertices.elementCount /*!!!.vertexOffset*/);
                        state.atomMapBuilder.endElement();
                    };
                    BallsAndSticksGeometryBuilder.addBond = function (b, state, bs) {
                        var aI = bs.info.bonds.atomAIndex[b], bI = bs.info.bonds.atomBIndex[b], type = bs.info.bonds.type[b];
                        if (state.params.hideHydrogens) {
                            var es = state.model.data.atoms.elementSymbol;
                            if (isHydrogen(es[aI]) || isHydrogen(es[bI])) {
                                return;
                            }
                        }
                        Vec3.set(bs.bondState.a, state.cX[aI], state.cY[aI], state.cZ[aI]);
                        Vec3.set(bs.bondState.b, state.cX[bI], state.cY[bI], state.cZ[bI]);
                        var r = +bs.bondRadius, o = 2 * r / 3, h = r / 2;
                        var bondState = bs.bondState;
                        switch (type) {
                            case 0 /* Unknown */:
                            case 1 /* Single */:
                            case 5 /* DisulfideBridge */:
                                BallsAndSticksGeometryBuilder.addBondPart(r, 0, 0, bondState);
                                break;
                            case 2 /* Double */:
                                BallsAndSticksGeometryBuilder.addBondPart(h, o, o, bondState);
                                BallsAndSticksGeometryBuilder.addBondPart(h, -o, -o, bondState);
                                break;
                            case 3 /* Triple */:
                                BallsAndSticksGeometryBuilder.addBondPart(h, 0, o, bondState);
                                var c = Math.cos(Math.PI / 3) * o, s = Math.sin(Math.PI / 3) * o;
                                BallsAndSticksGeometryBuilder.addBondPart(h, -c, -s, bondState);
                                BallsAndSticksGeometryBuilder.addBondPart(h, -c, s, bondState);
                                break;
                            case 4 /* Aromatic */:
                                BallsAndSticksGeometryBuilder.addBondPart(h / 2, o, o, bondState);
                                BallsAndSticksGeometryBuilder.addBondPart(h / 2, -o, -o, bondState);
                                BallsAndSticksGeometryBuilder.addBondPart(h / 2, -o, o, bondState);
                                BallsAndSticksGeometryBuilder.addBondPart(h / 2, o, -o, bondState);
                                break;
                            case 6 /* Metallic */:
                            case 7 /* Ion */:
                            case 8 /* Hydrogen */:
                                BallsAndSticksGeometryBuilder.addDashedBond(h, bondState);
                                break;
                        }
                    };
                    BallsAndSticksGeometryBuilder.addBondPart = function (r, oX, oY, state) {
                        var dir = Vec3.sub(state.dir, state.b, state.a);
                        var length = Vec3.magnitude(state.dir);
                        Vec3.set(state.scale, length, r, r);
                        Vec3.makeRotation(state.rotation, state.bondUpVector, dir);
                        state.offset[0] = 0;
                        state.offset[1] = oX;
                        state.offset[2] = oY;
                        Vec3.transformMat4(state.offset, state.offset, state.rotation);
                        Vec3.add(state.offset, state.offset, state.a);
                        GB.addRawTransformed(state.builder, state.bondTemplate, state.scale, state.offset, state.rotation);
                    };
                    BallsAndSticksGeometryBuilder.addDashedBond = function (r, state) {
                        GB.addDashedLine(state.builder, state.a, state.b, 0.15 /* MetalDashSize */, 0.15 /* MetalDashSize */, r);
                    };
                    BallsAndSticksGeometryBuilder.getEmptyBondsGeometry = function () {
                        var bondsGeometry = new Visualization.THREE.BufferGeometry();
                        bondsGeometry.addAttribute('position', new Visualization.THREE.BufferAttribute(new Float32Array(0), 3));
                        bondsGeometry.addAttribute('normal', new Visualization.THREE.BufferAttribute(new Float32Array(0), 3));
                        bondsGeometry.addAttribute('index', new Visualization.THREE.BufferAttribute(new Uint32Array(0), 1));
                        bondsGeometry.addAttribute('color', new Visualization.THREE.BufferAttribute(new Float32Array(0), 3));
                        return bondsGeometry;
                    };
                    BallsAndSticksGeometryBuilder.getBondsGeometry = function (state) {
                        var geom = GB.toBufferGeometry(state.bondBuilder);
                        Visualization.Geometry.addAttribute(geom, 'color', state.bondColors, 3);
                        return geom;
                    };
                    BallsAndSticksGeometryBuilder.getAtomsGeometry = function (state) {
                        var atomsGeometry = GB.toBufferGeometry(state.atomBuilder);
                        Visualization.Geometry.addAttribute(atomsGeometry, 'color', state.atomColors, 3);
                        var stateBuffer = new Float32Array(state.atomVertexCount);
                        var vertexStateBuffer = new Visualization.THREE.BufferAttribute(stateBuffer, 1);
                        atomsGeometry.addAttribute('vState', vertexStateBuffer);
                        var atomsPickGeometry = new Visualization.THREE.BufferGeometry();
                        atomsPickGeometry.addAttribute('position', atomsGeometry.getAttribute('position'));
                        atomsPickGeometry.addAttribute('index', atomsGeometry.getAttribute('index'));
                        atomsPickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(state.atomPickColors, 4));
                        return {
                            vertexStateBuffer: vertexStateBuffer,
                            atomsGeometry: atomsGeometry,
                            atomsPickGeometry: atomsPickGeometry,
                            atomVertexMap: state.atomMapBuilder.getMap()
                        };
                    };
                    BallsAndSticksGeometryBuilder.addAtoms = function (state, ctx) {
                        return __awaiter(this, void 0, void 0, function () {
                            var chunkSize, started, elementSymbol, hideHydrogens, start, _l, i, _b, aI, t;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        chunkSize = 2500;
                                        started = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        elementSymbol = state.model.data.atoms.elementSymbol;
                                        hideHydrogens = state.params.hideHydrogens;
                                        start = 0, _l = state.atomIndices.length;
                                        _a.label = 1;
                                    case 1:
                                        if (!(start < _l)) return [3 /*break*/, 4];
                                        for (i = start, _b = Math.min(start + chunkSize, state.atomIndices.length); i < _b; i++) {
                                            aI = state.atomIndices[i];
                                            if (hideHydrogens && isHydrogen(elementSymbol[aI])) {
                                                continue;
                                            }
                                            BallsAndSticksGeometryBuilder.addAtom(aI, state);
                                        }
                                        t = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        if (!(t - started > LiteMol.Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 3];
                                        started = t;
                                        return [4 /*yield*/, ctx.updateProgress('Adding atoms...', true, start, _l)];
                                    case 2:
                                        _a.sent();
                                        _a.label = 3;
                                    case 3:
                                        start += chunkSize;
                                        return [3 /*break*/, 1];
                                    case 4: return [2 /*return*/];
                                }
                            });
                        });
                    };
                    BallsAndSticksGeometryBuilder.addBondsChunks = function (state, bs, ctx) {
                        return __awaiter(this, void 0, void 0, function () {
                            var chunkSize, started, start, i, _b, t;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        chunkSize = 2500;
                                        started = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        start = 0;
                                        _a.label = 1;
                                    case 1:
                                        if (!(start < bs.bondCount)) return [3 /*break*/, 4];
                                        for (i = start, _b = Math.min(start + chunkSize, bs.bondCount); i < _b; i++) {
                                            BallsAndSticksGeometryBuilder.addBond(i, state, bs);
                                        }
                                        t = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        if (!(t - started > LiteMol.Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 3];
                                        started = t;
                                        return [4 /*yield*/, ctx.updateProgress('Adding bonds...', true, start, bs.bondCount)];
                                    case 2:
                                        _a.sent();
                                        _a.label = 3;
                                    case 3:
                                        start += chunkSize;
                                        return [3 /*break*/, 1];
                                    case 4: return [2 /*return*/];
                                }
                            });
                        });
                    };
                    BallsAndSticksGeometryBuilder.addBonds = function (state, ctx) {
                        return __awaiter(this, void 0, void 0, function () {
                            var bs;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        if (state.params.hideBonds) {
                                            return [2 /*return*/];
                                        }
                                        return [4 /*yield*/, ctx.updateProgress('Computing bonds...', true)];
                                    case 1:
                                        _a.sent();
                                        bs = new BondsBuildState(state);
                                        state.bs = bs;
                                        return [4 /*yield*/, BallsAndSticksGeometryBuilder.addBondsChunks(state, bs, ctx)];
                                    case 2:
                                        _a.sent();
                                        return [2 /*return*/];
                                }
                            });
                        });
                    };
                    BallsAndSticksGeometryBuilder.build = function (model, parameters, atomIndices, ctx) {
                        return __awaiter(this, void 0, void 0, function () {
                            var state, ret, atomGeometry;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Creating atoms...')];
                                    case 1:
                                        _a.sent();
                                        state = new BuildState(model, atomIndices, LiteMol.Core.Utils.extend({}, parameters, BallsAndSticks.DefaultBallsAndSticksModelParameters));
                                        return [4 /*yield*/, BallsAndSticksGeometryBuilder.addAtoms(state, ctx)];
                                    case 2:
                                        _a.sent();
                                        return [4 /*yield*/, BallsAndSticksGeometryBuilder.addBonds(state, ctx)];
                                    case 3:
                                        _a.sent();
                                        return [4 /*yield*/, ctx.updateProgress('Finalizing...')];
                                    case 4:
                                        _a.sent();
                                        ret = new BallsAndSticksGeometry();
                                        if (state.bs) {
                                            ret.bondsGeometry = BallsAndSticksGeometryBuilder.getBondsGeometry(state.bs);
                                        }
                                        else {
                                            ret.bondsGeometry = BallsAndSticksGeometryBuilder.getEmptyBondsGeometry();
                                        }
                                        atomGeometry = BallsAndSticksGeometryBuilder.getAtomsGeometry(state);
                                        ret.vertexStateBuffer = atomGeometry.vertexStateBuffer;
                                        ret.atomsGeometry = atomGeometry.atomsGeometry;
                                        ret.pickGeometry = atomGeometry.atomsPickGeometry;
                                        ret.atomVertexMap = atomGeometry.atomVertexMap;
                                        return [2 /*return*/, ret];
                                }
                            });
                        });
                    };
                    return BallsAndSticksGeometryBuilder;
                }());
                function buildGeometry(model, parameters, atomIndices, ctx) {
                    return BallsAndSticksGeometryBuilder.build(model, parameters, atomIndices, ctx);
                }
                BallsAndSticks.buildGeometry = buildGeometry;
                var BallsAndSticksGeometry = /** @class */ (function (_super) {
                    __extends(BallsAndSticksGeometry, _super);
                    function BallsAndSticksGeometry() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.atomsGeometry = void 0;
                        _this.bondsGeometry = void 0;
                        _this.pickGeometry = void 0;
                        _this.atomVertexMap = void 0;
                        _this.vertexStateBuffer = void 0;
                        return _this;
                    }
                    BallsAndSticksGeometry.prototype.dispose = function () {
                        this.atomsGeometry.dispose();
                        this.bondsGeometry.dispose();
                        this.pickGeometry.dispose();
                    };
                    return BallsAndSticksGeometry;
                }(Visualization.GeometryBase));
                BallsAndSticks.BallsAndSticksGeometry = BallsAndSticksGeometry;
            })(BallsAndSticks = Molecule.BallsAndSticks || (Molecule.BallsAndSticks = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var Cartoons;
            (function (Cartoons) {
                var Geometry;
                (function (Geometry) {
                    var Data = /** @class */ (function (_super) {
                        __extends(Data, _super);
                        function Data() {
                            var _this = _super !== null && _super.apply(this, arguments) || this;
                            _this.geometry = void 0;
                            _this.pickGeometry = void 0;
                            _this.gapsGeometry = void 0;
                            _this.directionConesGeometry = void 0;
                            _this.vertexMap = void 0;
                            _this.vertexStateBuffer = void 0;
                            return _this;
                        }
                        Data.prototype.dispose = function () {
                            this.geometry.dispose();
                            this.pickGeometry.dispose();
                            if (this.gapsGeometry) {
                                this.gapsGeometry.dispose();
                            }
                            if (this.directionConesGeometry) {
                                this.directionConesGeometry.dispose();
                            }
                        };
                        return Data;
                    }(Visualization.GeometryBase));
                    Geometry.Data = Data;
                    function create(model, atomIndices, linearSegments, parameters, isTrace, computation) {
                        return __awaiter(this, void 0, void 0, function () {
                            var params, ctx, ret, _i, _a, k;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        params = LiteMol.Core.Utils.extend({}, parameters, Geometry.CartoonsGeometryParams.Default);
                                        ctx = {
                                            computation: computation,
                                            model: model,
                                            atomIndices: atomIndices,
                                            linearSegments: linearSegments,
                                            parameters: parameters,
                                            isTrace: isTrace,
                                            params: params,
                                            state: new Geometry.CartoonsGeometryState(params, model.data.residues.count),
                                            units: void 0,
                                            strandArrays: {
                                                startIndex: model.data.residues.atomStartIndex,
                                                endIndex: model.data.residues.atomEndIndex,
                                                x: model.positions.x, y: model.positions.y, z: model.positions.z,
                                                name: model.data.atoms.name
                                            },
                                            strandTemplate: void 0,
                                            builder: new Geometry.Builder(),
                                            geom: new Data()
                                        };
                                        return [4 /*yield*/, ctx.computation.updateProgress('Building units...')];
                                    case 1:
                                        _b.sent();
                                        ctx.units = Geometry.CartoonAsymUnit.buildUnits(ctx.model, ctx.atomIndices, ctx.linearSegments);
                                        return [4 /*yield*/, Geometry.buildUnitsAsync(ctx)];
                                    case 2:
                                        _b.sent();
                                        if (ctx.strandTemplate)
                                            ctx.strandTemplate.geometry.dispose();
                                        ctx.geom.vertexMap = ctx.state.vertexMap.getMap();
                                        return [4 /*yield*/, ctx.computation.updateProgress('Creating geometry...')];
                                    case 3:
                                        _b.sent();
                                        Geometry.createGeometry(ctx);
                                        ret = ctx.geom;
                                        // help the GC
                                        for (_i = 0, _a = Object.keys(ctx); _i < _a.length; _i++) {
                                            k = _a[_i];
                                            if (!Object.prototype.hasOwnProperty.call(ctx, k))
                                                continue;
                                            ctx[k] = void 0;
                                        }
                                        return [2 /*return*/, ret];
                                }
                            });
                        });
                    }
                    Geometry.create = create;
                })(Geometry = Cartoons.Geometry || (Cartoons.Geometry = {}));
            })(Cartoons = Molecule.Cartoons || (Molecule.Cartoons = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var Cartoons;
            (function (Cartoons) {
                var Geometry;
                (function (Geometry) {
                    var ArrayBuilder = LiteMol.Core.Utils.ArrayBuilder;
                    var CartoonAsymUnit = /** @class */ (function () {
                        function CartoonAsymUnit(model, elements, linearSegmentCount) {
                            this.model = model;
                            this.elements = elements;
                            this.linearSegmentCount = linearSegmentCount;
                            this.tempA = new Visualization.THREE.Vector3();
                            this.tempB = new Visualization.THREE.Vector3();
                            this.tempC = new Visualization.THREE.Vector3();
                            this.controlPoints = new Float32Array(0);
                            this.torsionVectors = new Float32Array(0);
                            this.normalVectors = new Float32Array(0);
                            this.residueCount = 0;
                            this.structureStarts = LiteMol.Core.Utils.FastSet.create();
                            this.structureEnds = LiteMol.Core.Utils.FastSet.create();
                            this.residueType = [];
                            this.residueIndex = new Int32Array(0);
                            this.backboneOnly = false;
                            this.startResidueIndex = -1;
                            this.endResidueIndex = -1;
                            for (var _i = 0, _a = this.elements; _i < _a.length; _i++) {
                                var e = _a[_i];
                                this.residueCount += e.endResidueIndex - e.startResidueIndex;
                            }
                            this.startResidueIndex = this.elements[0].startResidueIndex;
                            this.endResidueIndex = this.elements[this.elements.length - 1].endResidueIndex - 1;
                            var builder = new ContolPointsBuilder(this.residueCount);
                            this.controlPointsBuilder = ArrayBuilder.forVertex3D(this.residueCount * this.linearSegmentCount + 1);
                            this.torsionVectorsBuilder = ArrayBuilder.forVertex3D(this.residueCount * this.linearSegmentCount + 1);
                            this.normalVectorsBuilder = ArrayBuilder.forVertex3D(this.residueCount * this.linearSegmentCount + 1);
                            this.createControlPoints(builder);
                        }
                        CartoonAsymUnit.prototype.createControlPoints = function (builder) {
                            this.initPositions(builder);
                            this.initControlsPoints(builder);
                            this.computeSplines(builder);
                            this.controlPoints = this.controlPointsBuilder.array;
                            this.torsionVectors = this.torsionVectorsBuilder.array;
                            this.normalVectors = this.normalVectorsBuilder.array;
                            this.controlPointsBuilder = null;
                            this.torsionVectorsBuilder = null;
                            this.normalVectorsBuilder = null;
                        };
                        CartoonAsymUnit.prototype.initPositions = function (builder) {
                            var residues = this.model.data.residues, atoms = this.model.data.atoms, positions = this.model.positions, arrays = { atomStartIndex: residues.atomStartIndex, atomEndIndex: residues.atomEndIndex, name: atoms.name, x: positions.x, y: positions.y, z: positions.z }, residueType = [], offset = 0, i = 0;
                            var bbOnlyCount = 0, residueCount = 0;
                            for (var _i = 0, _a = this.elements; _i < _a.length; _i++) {
                                var e = _a[_i];
                                this.structureStarts.add(e.startResidueIndex);
                                this.structureEnds.add(e.endResidueIndex - 1);
                                for (i = e.startResidueIndex; i < e.endResidueIndex; i++) {
                                    residueCount++;
                                    var bbOnly = builder.addResidue(i, arrays, e.type);
                                    if (bbOnly && (e.type === 1 /* Helix */ || e.type === 3 /* Sheet */ || e.type === 5 /* Strand */)) {
                                        bbOnlyCount++;
                                    }
                                    residueType[residueType.length] = e.type;
                                }
                            }
                            this.backboneOnly = bbOnlyCount > (residueCount / 4 - 1);
                            this.residueIndex = new Int32Array(this.residueCount);
                            for (var _d = 0, _e = this.elements; _d < _e.length; _d++) {
                                var e = _e[_d];
                                for (i = e.startResidueIndex; i < e.endResidueIndex; i++) {
                                    this.residueIndex[offset++] = i;
                                }
                            }
                            this.residueType = residueType;
                            builder.finishResidues();
                            var len = this.residueCount;
                            builder.residueType[0] = builder.residueType[2];
                            builder.residueType[1] = builder.residueType[3];
                            builder.residueType[builder.residueType.length - 2] = builder.residueType[builder.residueType.length - 4];
                            builder.residueType[builder.residueType.length - 1] = builder.residueType[builder.residueType.length - 3];
                            if (len > 2) {
                                var a = 2, b = 3, c = 4;
                                if (builder.residueType[0] !== 5 /* Strand */) {
                                    this.reflectPositions(builder.uPositions, 0, 1, a, b, b, c, 0.4, 0.6);
                                    this.reflectPositions(builder.vPositions, 0, 1, a, b, b, c, 0.4, 0.6);
                                }
                                else {
                                    this.reflectPositions(builder.uPositions, 1, 0, a, b, b, c, 0.5, 0.5);
                                    this.reflectPositions(builder.vPositions, 1, 0, a, b, b, c, 0.5, 0.5);
                                }
                                a = len + 1;
                                b = len;
                                c = len - 1;
                                if (builder.residueType[len - 1] !== 5 /* Strand */) {
                                    this.reflectPositions(builder.uPositions, len + 2, len + 3, a, b, b, c, 0.4, 0.6);
                                    this.reflectPositions(builder.vPositions, len + 2, len + 3, a, b, b, c, 0.4, 0.6);
                                }
                                else {
                                    this.reflectPositions(builder.uPositions, len + 2, len + 3, a, b, b, c, 0.5, 0.5);
                                    this.reflectPositions(builder.vPositions, len + 2, len + 3, a, b, b, c, 0.5, 0.5);
                                }
                            }
                            else if (len === 2) {
                                for (i = 0; i < 2; i++) {
                                    builder.uPositions[3 * i] = builder.uPositions[6];
                                    builder.uPositions[3 * i + 1] = builder.uPositions[7];
                                    builder.uPositions[3 * i + 2] = builder.uPositions[8];
                                    builder.vPositions[3 * i] = builder.vPositions[6];
                                    builder.vPositions[3 * i + 1] = builder.vPositions[7];
                                    builder.vPositions[3 * i + 2] = builder.vPositions[8];
                                    builder.uPositions[(len + 2) * 3 + 3 * i] = builder.uPositions[(len + 1) * 3];
                                    builder.uPositions[(len + 2) * 3 + 3 * i + 1] = builder.uPositions[(len + 1) * 3 + 1];
                                    builder.uPositions[(len + 2) * 3 + 3 * i + 2] = builder.uPositions[(len + 1) * 3 + 2];
                                    builder.vPositions[(len + 2) * 3 + 3 * i] = builder.vPositions[(len + 1) * 3];
                                    builder.vPositions[(len + 2) * 3 + 3 * i + 1] = builder.vPositions[(len + 1) * 3 + 1];
                                    builder.vPositions[(len + 2) * 3 + 3 * i + 2] = builder.vPositions[(len + 1) * 3 + 2];
                                }
                            }
                            else {
                                var d = [builder.uPositions[6] - builder.vPositions[6],
                                    builder.uPositions[7] - builder.vPositions[7],
                                    builder.uPositions[8] - builder.vPositions[8]];
                                for (var i_3 = 0; i_3 < 2; i_3++) {
                                    for (var j = 0; j < 3; j++) {
                                        builder.uPositions[3 * i_3 + j] = builder.uPositions[6 + j] - 0.5 * (i_3 + 1) * d[j];
                                        builder.uPositions[9 + 3 * i_3 + j] = builder.uPositions[6 + j] + 0.5 * (i_3 + 1) * d[j];
                                        builder.vPositions[3 * i_3 + j] = builder.vPositions[6 + j] + 0.5 * (i_3 + 1) * d[j];
                                        builder.vPositions[9 + 3 * i_3 + j] = builder.vPositions[6 + j] - 0.5 * (i_3 + 1) * d[j];
                                    }
                                }
                                //state.uPositions[0] = state.uPositions[6] - dx;
                                //state.uPositions[9] = state.uPositions[6] - dx;                
                                //console.log(state.uPositions, state.vPositions);
                            }
                        };
                        CartoonAsymUnit.prototype.initControlsPoints = function (builder) {
                            var previousD = new Visualization.THREE.Vector3(), len = builder.uvLength - 1, a = new Visualization.THREE.Vector3(), b = new Visualization.THREE.Vector3(), c = new Visualization.THREE.Vector3(), d = new Visualization.THREE.Vector3(), ca1 = new Visualization.THREE.Vector3(), o1 = new Visualization.THREE.Vector3(), ca2 = new Visualization.THREE.Vector3(), p = new Visualization.THREE.Vector3(), helixType = 1 /* Helix */;
                            for (var i = 0; i < len; i++) {
                                ca1.set(builder.uPositions[3 * i], builder.uPositions[3 * i + 1], builder.uPositions[3 * i + 2]);
                                o1.set(builder.vPositions[3 * i], builder.vPositions[3 * i + 1], builder.vPositions[3 * i + 2]);
                                i++;
                                ca2.set(builder.uPositions[3 * i], builder.uPositions[3 * i + 1], builder.uPositions[3 * i + 2]);
                                i--;
                                p.set((ca1.x + ca2.x) / 2, (ca1.y + ca2.y) / 2, (ca1.z + ca2.z) / 2);
                                a.subVectors(ca2, ca1);
                                b.subVectors(o1, ca1);
                                c.crossVectors(a, b);
                                d.crossVectors(c, a);
                                c.normalize();
                                d.normalize();
                                if (builder.residueType[i] === helixType && builder.residueType[i + 1] === helixType) {
                                    p.set(p.x + 1.5 * c.x, p.y + 1.5 * c.y, p.z + 1.5 * c.z);
                                }
                                if (i > 0 && d.angleTo(previousD) > Math.PI / 2) {
                                    d.negate();
                                }
                                previousD.copy(d);
                                a.addVectors(p, d);
                                builder.addControlPoint(p, a);
                            }
                            builder.finishContols();
                        };
                        CartoonAsymUnit.prototype.computeSplines = function (builder) {
                            var previousControlPoint = new Visualization.THREE.Vector3(), controlPoint = new Visualization.THREE.Vector3(), torsionPoint = new Visualization.THREE.Vector3(), len = builder.residueCount, pPositions = builder.pPositions, dPositions = builder.dPositions, p1 = new Visualization.THREE.Vector3(), p2 = new Visualization.THREE.Vector3(), p3 = new Visualization.THREE.Vector3(), p4 = new Visualization.THREE.Vector3(), d1 = new Visualization.THREE.Vector3(), d2 = new Visualization.THREE.Vector3(), d3 = new Visualization.THREE.Vector3(), d4 = new Visualization.THREE.Vector3(), previousTorsionPoint = new Visualization.THREE.Vector3(), extrapolatedControlPoint = new Visualization.THREE.Vector3();
                            for (var i = 0; i < len; i++) {
                                p1.set(pPositions[3 * i], pPositions[3 * i + 1], pPositions[3 * i + 2]);
                                i++;
                                p2.set(pPositions[3 * i], pPositions[3 * i + 1], pPositions[3 * i + 2]);
                                i++;
                                p3.set(pPositions[3 * i], pPositions[3 * i + 1], pPositions[3 * i + 2]);
                                i++;
                                p4.set(pPositions[3 * i], pPositions[3 * i + 1], pPositions[3 * i + 2]);
                                i = i - 3;
                                d1.set(dPositions[3 * i], dPositions[3 * i + 1], dPositions[3 * i + 2]);
                                i++;
                                d2.set(dPositions[3 * i], dPositions[3 * i + 1], dPositions[3 * i + 2]);
                                i++;
                                d3.set(dPositions[3 * i], dPositions[3 * i + 1], dPositions[3 * i + 2]);
                                i++;
                                d4.set(dPositions[3 * i], dPositions[3 * i + 1], dPositions[3 * i + 2]);
                                i = i - 3;
                                for (var j = 1; j <= this.linearSegmentCount; j++) {
                                    var t = j * 1.0 / this.linearSegmentCount;
                                    if (t < 0.5) {
                                        CartoonAsymUnit.spline(controlPoint, p1, p2, p3, t + 0.5);
                                        CartoonAsymUnit.spline(torsionPoint, d1, d2, d3, t + 0.5);
                                    }
                                    else {
                                        CartoonAsymUnit.spline(controlPoint, p2, p3, p4, t - 0.5);
                                        CartoonAsymUnit.spline(torsionPoint, d2, d3, d4, t - 0.5);
                                    }
                                    if (i === 0 && j === 1) {
                                        CartoonAsymUnit.spline(previousControlPoint, p1, p2, p3, 0.5);
                                        CartoonAsymUnit.spline(previousTorsionPoint, d1, d2, d3, 0.5);
                                        CartoonAsymUnit.reflect(extrapolatedControlPoint, previousControlPoint, controlPoint, 1);
                                        this.addSplineNode(extrapolatedControlPoint, previousControlPoint, previousTorsionPoint);
                                    }
                                    this.addSplineNode(previousControlPoint, controlPoint, torsionPoint);
                                    previousControlPoint.copy(controlPoint);
                                }
                            }
                        };
                        CartoonAsymUnit.prototype.addSplineNode = function (previousControlPoint, controlPoint, torsionPoint) {
                            ArrayBuilder.add3(this.controlPointsBuilder, controlPoint.x, controlPoint.y, controlPoint.z);
                            var torsionVector = this.tempA.subVectors(torsionPoint, controlPoint);
                            torsionVector.normalize();
                            ArrayBuilder.add3(this.torsionVectorsBuilder, torsionVector.x, torsionVector.y, torsionVector.z);
                            var controlVector = this.tempB.subVectors(controlPoint, previousControlPoint);
                            var normalVector = this.tempC.crossVectors(torsionVector, controlVector);
                            normalVector.normalize();
                            ArrayBuilder.add3(this.normalVectorsBuilder, normalVector.x, normalVector.y, normalVector.z);
                        };
                        CartoonAsymUnit.prototype.reflectPositions = function (xs, u, v, a, b, c, d, r1, r2) {
                            this.tempA.set(xs[3 * a], xs[3 * a + 1], xs[3 * a + 2]);
                            this.tempB.set(xs[3 * b], xs[3 * b + 1], xs[3 * b + 2]);
                            CartoonAsymUnit.reflect(this.tempC, this.tempA, this.tempB, r1);
                            xs[3 * u] = this.tempC.x;
                            xs[3 * u + 1] = this.tempC.y;
                            xs[3 * u + 2] = this.tempC.z;
                            this.tempA.set(xs[3 * c], xs[3 * c + 1], xs[3 * c + 2]);
                            this.tempB.set(xs[3 * d], xs[3 * d + 1], xs[3 * d + 2]);
                            CartoonAsymUnit.reflect(this.tempC, this.tempA, this.tempB, r2);
                            xs[3 * v] = this.tempC.x;
                            xs[3 * v + 1] = this.tempC.y;
                            xs[3 * v + 2] = this.tempC.z;
                        };
                        return CartoonAsymUnit;
                    }());
                    Geometry.CartoonAsymUnit = CartoonAsymUnit;
                    (function (CartoonAsymUnit) {
                        function reflect(target, p1, p2, amount) {
                            target.set(p1.x - amount * (p2.x - p1.x), p1.y - amount * (p2.y - p1.y), p1.z - amount * (p2.z - p1.z));
                        }
                        CartoonAsymUnit.reflect = reflect;
                        function spline(target, p1, p2, p3, t) {
                            var a = Math.pow(1 - t, 2) / 2;
                            var c = Math.pow(t, 2) / 2;
                            var b = 1 - a - c;
                            var x = a * p1.x + b * p2.x + c * p3.x;
                            var y = a * p1.y + b * p2.y + c * p3.y;
                            var z = a * p1.z + b * p2.z + c * p3.z;
                            target.set(x, y, z);
                        }
                        CartoonAsymUnit.spline = spline;
                        function maskSplit(element, mask, target) {
                            var current = new LiteMol.Core.Structure.SecondaryStructureElement(element.type, element.startResidueId, element.endResidueId), start = element.startResidueIndex, end = element.endResidueIndex;
                            for (var i = start; i < end; i++) {
                                if (!mask[i])
                                    continue;
                                if (current.startResidueIndex !== i) {
                                    current = new LiteMol.Core.Structure.SecondaryStructureElement(element.type, element.startResidueId, element.endResidueId);
                                    current.startResidueIndex = i;
                                }
                                while (i < end && mask[i]) {
                                    i++;
                                }
                                current.endResidueIndex = i;
                                target[target.length] = current;
                            }
                        }
                        CartoonAsymUnit.maskSplit = maskSplit;
                        function isCartoonLike(atomIndices, start, end, name, a, b, isAmk) {
                            var aU = false, aV = false, hasP = false;
                            for (var i = start; i < end; i++) {
                                var n = name[atomIndices[i]];
                                if (!aU && n === a) {
                                    aU = true;
                                }
                                else if (!aV && n === b) {
                                    aV = true;
                                }
                                if (aU && aV)
                                    return true;
                                if (n === 'P') {
                                    hasP = true;
                                }
                            }
                            if (isAmk)
                                return aU;
                            return hasP;
                        }
                        CartoonAsymUnit.isCartoonLike = isCartoonLike;
                        function createMask(model, atomIndices) {
                            var ret = new Uint8Array(model.data.residues.count);
                            var _a = model.data.atoms, residueIndex = _a.residueIndex, name = _a.name;
                            var ssIndex = model.data.residues.secondaryStructureIndex;
                            var ss = model.data.secondaryStructure;
                            for (var i = 0, _b = atomIndices.length - 1; i < _b; i++) {
                                var aI = atomIndices[i];
                                var rStart = i;
                                var residue = residueIndex[aI];
                                i++;
                                while (residue === residueIndex[atomIndices[i]])
                                    i++;
                                var s = ss[ssIndex[residue]].type;
                                if (s === 0 /* None */)
                                    continue;
                                if (s === 5 /* Strand */) {
                                    ret[residue] = +CartoonAsymUnit.isCartoonLike(atomIndices, rStart, i, name, "O5'", "C3'", false);
                                }
                                else {
                                    ret[residue] = +CartoonAsymUnit.isCartoonLike(atomIndices, rStart, i, name, "CA", "O", true);
                                }
                                i--;
                            }
                            return ret;
                        }
                        CartoonAsymUnit.createMask = createMask;
                        function isUnknownSecondaryStructure(model) {
                            var hasSeq = false;
                            for (var _i = 0, _a = model.data.secondaryStructure; _i < _a.length; _i++) {
                                var e = _a[_i];
                                if (e.type === 1 /* Helix */
                                    || e.type === 3 /* Sheet */
                                    || e.type === 2 /* Turn */) {
                                    return false;
                                }
                                if (e.type === 4 /* AminoSeq */) {
                                    hasSeq = true;
                                }
                            }
                            return hasSeq;
                        }
                        function approximateSecondaryStructure(model, parent) {
                            if (parent.type !== 4 /* AminoSeq */)
                                return [parent];
                            var elements = [];
                            var name = model.data.atoms.name;
                            var _a = model.data.residues, atomStartIndex = _a.atomStartIndex, atomEndIndex = _a.atomEndIndex;
                            var trace = new Int32Array(parent.endResidueIndex - parent.startResidueIndex), offset = 0;
                            var isOk = true;
                            for (var i = parent.startResidueIndex, _b = parent.endResidueIndex; i < _b; i++) {
                                var foundCA = false, foundO = false;
                                for (var j = atomStartIndex[i], _c = atomEndIndex[i]; j < _c; j++) {
                                    if (name[j] === 'CA') {
                                        if (!foundCA)
                                            trace[offset++] = j;
                                        foundCA = true;
                                    }
                                    else if (name[j] === 'O') {
                                        foundO = true;
                                    }
                                    if (foundO && foundCA)
                                        break;
                                }
                                if (!foundCA || !foundO) {
                                    isOk = false;
                                    break;
                                }
                            }
                            if (!isOk)
                                return [parent];
                            zhangSkolnickSStrace(model, trace, parent, elements);
                            return elements;
                        }
                        var ZhangHelixDistance = [5.45, 5.18, 6.37];
                        var ZhangHelixDelta = 2.1;
                        var ZhangSheetDistance = [6.1, 10.4, 13.0];
                        var ZhangSheetDelta = 1.42;
                        var ZhangP1 = new Visualization.THREE.Vector3(0, 0, 0);
                        var ZhangP2 = new Visualization.THREE.Vector3(0, 0, 0);
                        function zhangSkolnickSStrace(model, trace, parent, elements) {
                            var mask = new Int32Array(trace.length);
                            var hasSS = false;
                            var residueIndex = model.data.atoms.residueIndex;
                            for (var i = 0, _l = trace.length; i < _l; i++) {
                                if (zhangSkolnickSSresidue(model, trace, i, ZhangHelixDistance, ZhangHelixDelta)) {
                                    mask[i] = 1 /* Helix */;
                                    hasSS = true;
                                }
                                else if (zhangSkolnickSSresidue(model, trace, i, ZhangSheetDistance, ZhangSheetDelta)) {
                                    mask[i] = 3 /* Sheet */;
                                    hasSS = true;
                                }
                                else {
                                    mask[i] = parent.type;
                                }
                            }
                            if (!hasSS) {
                                elements.push(parent);
                                return;
                            }
                            // filter 1-length elements
                            for (var i = 0, _l = mask.length; i < _l; i++) {
                                var m = mask[i];
                                if (m === parent.type)
                                    continue;
                                var j = i + 1;
                                while (j < _l && m === mask[j]) {
                                    j++;
                                }
                                if (j - i > 1) {
                                    i = j - 1;
                                    continue;
                                }
                                for (var k = i; k < j; k++)
                                    mask[k] = parent.type;
                                i = j - 1;
                            }
                            for (var i = 0, _l = mask.length; i < _l; i++) {
                                var m = mask[i];
                                var j = i + 1;
                                while (j < _l && m === mask[j]) {
                                    j++;
                                }
                                var e = new LiteMol.Core.Structure.SecondaryStructureElement(m, new LiteMol.Core.Structure.PolyResidueIdentifier('', i, null), new LiteMol.Core.Structure.PolyResidueIdentifier('', j, null));
                                e.startResidueIndex = residueIndex[trace[i]];
                                e.endResidueIndex = residueIndex[trace[j - 1]] + 1;
                                elements.push(e);
                                i = j - 1;
                            }
                        }
                        function zhangSkolnickSSresidue(model, trace, i, distances, delta) {
                            var len = trace.length;
                            var _a = model.positions, x = _a.x, y = _a.y, z = _a.z;
                            var u = ZhangP1, v = ZhangP2;
                            for (var j = Math.max(0, i - 2); j <= i; j++) {
                                for (var k = 2; k < 5; k++) {
                                    if (j + k >= len) {
                                        continue;
                                    }
                                    var a = trace[j], b = trace[j + k];
                                    u.set(x[a], y[a], z[a]);
                                    v.set(x[b], y[b], z[b]);
                                    if (Math.abs(u.distanceTo(v) - distances[k - 2]) > delta) {
                                        return false;
                                    }
                                }
                            }
                            return true;
                        }
                        function throwIfEmpty(ss) {
                            if (ss.length === 0) {
                                throw "Cartoons cannot be constructred from this model/selection.";
                            }
                        }
                        function buildUnits(model, atomIndices, linearSegmentCount) {
                            var mask = createMask(model, atomIndices);
                            var ss = [];
                            var isUnknownSS = isUnknownSecondaryStructure(model);
                            for (var _i = 0, _a = model.data.secondaryStructure; _i < _a.length; _i++) {
                                var e = _a[_i];
                                if (isUnknownSS) {
                                    var approx = approximateSecondaryStructure(model, e);
                                    for (var _d = 0, approx_1 = approx; _d < approx_1.length; _d++) {
                                        var f = approx_1[_d];
                                        CartoonAsymUnit.maskSplit(f, mask, ss);
                                    }
                                }
                                else {
                                    CartoonAsymUnit.maskSplit(e, mask, ss);
                                }
                            }
                            throwIfEmpty(ss);
                            var previous = ss[0], asymId = model.data.residues.asymId, authSeqNumber = model.data.residues.authSeqNumber, currentElements = [], units = [], none = 0 /* None */;
                            if (previous.type === none) {
                                previous = null;
                            }
                            for (var _e = 0, ss_2 = ss; _e < ss_2.length; _e++) {
                                var e = ss_2[_e];
                                if (e.type === none) {
                                    if (currentElements.length > 0) {
                                        units.push(new CartoonAsymUnit(model, currentElements, linearSegmentCount));
                                    }
                                    previous = null;
                                    currentElements = [];
                                }
                                else {
                                    if (previous === null)
                                        previous = e;
                                    if (asymId[previous.endResidueIndex - 1] !== asymId[e.startResidueIndex]
                                        || (previous !== e && authSeqNumber[e.startResidueIndex] - authSeqNumber[previous.endResidueIndex - 1] > 1)
                                        || (previous.startResidueIndex !== e.startResidueIndex && (e.startResidueIndex - previous.endResidueIndex > 0))) {
                                        if (currentElements.length > 0) {
                                            units.push(new CartoonAsymUnit(model, currentElements, linearSegmentCount));
                                        }
                                        else if (previous !== null) {
                                            units.push(new CartoonAsymUnit(model, [previous], linearSegmentCount));
                                        }
                                        previous = null;
                                        currentElements = [e];
                                    }
                                    else {
                                        currentElements[currentElements.length] = e;
                                    }
                                }
                                previous = e;
                            }
                            if (currentElements.length > 0) {
                                units.push(new CartoonAsymUnit(model, currentElements, linearSegmentCount));
                            }
                            return units; // [units[units.length - 1]];
                        }
                        CartoonAsymUnit.buildUnits = buildUnits;
                    })(CartoonAsymUnit = Geometry.CartoonAsymUnit || (Geometry.CartoonAsymUnit = {}));
                    var ContolPointsBuilder = /** @class */ (function () {
                        function ContolPointsBuilder(residueCount) {
                            this.typeBuilder = ArrayBuilder.forArray(10000);
                            this.residueType = [];
                            this.uPositions = new Float32Array(0);
                            this.vPositions = new Float32Array(0);
                            this.pPositions = new Float32Array(0);
                            this.dPositions = new Float32Array(0);
                            this.uvLength = 0;
                            this.residueCount = 0;
                            this.typeBuilder = ArrayBuilder.forArray(residueCount + 4);
                            this.uPositionsBuilder = ArrayBuilder.forVertex3D(residueCount + 4);
                            this.vPositionsBuilder = ArrayBuilder.forVertex3D(residueCount + 4);
                            this.pPositionsBuilder = ArrayBuilder.forVertex3D(residueCount + 4);
                            this.dPositionsBuilder = ArrayBuilder.forVertex3D(residueCount + 4);
                            ArrayBuilder.add(this.typeBuilder, 0 /* None */);
                            ArrayBuilder.add(this.typeBuilder, 0 /* None */);
                            ArrayBuilder.add3(this.uPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.uPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.vPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.vPositionsBuilder, 0, 0, 0);
                        }
                        ContolPointsBuilder.prototype.addResidue = function (rIndex, arrays, sType) {
                            var start = arrays.atomStartIndex[rIndex], end = arrays.atomEndIndex[rIndex], aU = false, aV = false;
                            var name = arrays.name;
                            if (sType !== 5 /* Strand */) {
                                for (var i = start; i < end; i++) {
                                    if (!aU && name[i] === "CA") {
                                        ArrayBuilder.add3(this.uPositionsBuilder, arrays.x[i], arrays.y[i], arrays.z[i]);
                                        aU = true;
                                    }
                                    else if (!aV && name[i] === "O") {
                                        ArrayBuilder.add3(this.vPositionsBuilder, arrays.x[i], arrays.y[i], arrays.z[i]);
                                        aV = true;
                                    }
                                    if (aU && aV)
                                        break;
                                }
                            }
                            else {
                                if (end - start === 1) {
                                    // has to be P atom
                                    ArrayBuilder.add3(this.uPositionsBuilder, arrays.x[start], arrays.y[start], arrays.z[start]);
                                    aU = true;
                                }
                                else {
                                    var pIndex = -1;
                                    for (var i = start; i < end; i++) {
                                        if (!aU && name[i] === "O5'") {
                                            ArrayBuilder.add3(this.uPositionsBuilder, arrays.x[i], arrays.y[i], arrays.z[i]);
                                            aU = true;
                                        }
                                        else if (!aV && name[i] === "C3'") {
                                            ArrayBuilder.add3(this.vPositionsBuilder, arrays.x[i], arrays.y[i], arrays.z[i]);
                                            aV = true;
                                        }
                                        if (name[i] === "P") {
                                            pIndex = i;
                                        }
                                        if (aU && aV)
                                            break;
                                    }
                                    if (!aU && !aV && pIndex >= 0) {
                                        ArrayBuilder.add3(this.uPositionsBuilder, arrays.x[pIndex], arrays.y[pIndex], arrays.z[pIndex]);
                                        aU = true;
                                    }
                                }
                            }
                            var backboneOnly = false;
                            if (!aV) {
                                var arr = this.uPositionsBuilder.array, len = arr.length;
                                ArrayBuilder.add3(this.vPositionsBuilder, arr[len - 3], arr[len - 2], arr[len - 1]);
                                backboneOnly = true;
                            }
                            else if (!aU) {
                                var arr = this.vPositionsBuilder.array, len = arr.length;
                                ArrayBuilder.add3(this.uPositionsBuilder, arr[len - 3], arr[len - 2], arr[len - 1]);
                                backboneOnly = true;
                            }
                            ArrayBuilder.add(this.typeBuilder, sType);
                            return backboneOnly;
                        };
                        ContolPointsBuilder.prototype.finishResidues = function () {
                            ArrayBuilder.add(this.typeBuilder, 0 /* None */);
                            ArrayBuilder.add(this.typeBuilder, 0 /* None */);
                            ArrayBuilder.add3(this.uPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.uPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.vPositionsBuilder, 0, 0, 0);
                            ArrayBuilder.add3(this.vPositionsBuilder, 0, 0, 0);
                            this.residueType = this.typeBuilder.array;
                            this.uPositions = this.uPositionsBuilder.array;
                            this.vPositions = this.vPositionsBuilder.array;
                            this.typeBuilder = null;
                            this.uPositionsBuilder = null;
                            this.vPositionsBuilder = null;
                            this.uvLength = this.residueType.length;
                            this.residueCount = this.uvLength - 4;
                        };
                        ContolPointsBuilder.prototype.addControlPoint = function (p, d) {
                            ArrayBuilder.add3(this.pPositionsBuilder, p.x, p.y, p.z);
                            ArrayBuilder.add3(this.dPositionsBuilder, d.x, d.y, d.z);
                        };
                        ContolPointsBuilder.prototype.finishContols = function () {
                            this.pPositions = this.pPositionsBuilder.array;
                            this.dPositions = this.dPositionsBuilder.array;
                            this.pPositionsBuilder = null;
                            this.dPositionsBuilder = null;
                        };
                        return ContolPointsBuilder;
                    }());
                })(Geometry = Cartoons.Geometry || (Cartoons.Geometry = {}));
            })(Cartoons = Molecule.Cartoons || (Molecule.Cartoons = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var Cartoons;
            (function (Cartoons) {
                var Geometry;
                (function (Geometry) {
                    var CartoonsGeometryParams = /** @class */ (function () {
                        function CartoonsGeometryParams() {
                            this.radialSegmentCount = 10;
                            this.turnWidth = 0.1;
                            this.strandWidth = 0.15;
                            this.nucleotideStrandLineWidth = 0.15;
                            this.nucleotideStrandFactor = 3;
                            this.helixWidth = 1.1;
                            this.helixHeight = 0.1;
                            this.sheetWidth = 1.1;
                            this.sheetHeight = 0.1;
                            this.arrowWidth = 1.7;
                            this.tessalation = 2;
                        }
                        CartoonsGeometryParams.Default = new CartoonsGeometryParams();
                        return CartoonsGeometryParams;
                    }());
                    Geometry.CartoonsGeometryParams = CartoonsGeometryParams;
                    var GB = Visualization.Geometry.Builder;
                    var CartoonsGeometryState = /** @class */ (function () {
                        function CartoonsGeometryState(params, residueCount) {
                            this.params = params;
                            this.residueCount = residueCount;
                            this.residueIndex = 0;
                            this.builder = GB.createDynamic(this.residueCount * 8, this.residueCount * 16);
                            this.vs = this.builder.vertices;
                            this.is = this.builder.indices;
                            this.gapsBuilder = GB.createDynamic(256, 512);
                            this.dCones = GB.createDynamic(1, 1);
                            this.dConesInit = false;
                            this.translationMatrix = new Visualization.THREE.Matrix4();
                            this.scaleMatrix = new Visualization.THREE.Matrix4();
                            this.rotationMatrix = new Visualization.THREE.Matrix4();
                            this.invMatrix = new Visualization.THREE.Matrix4();
                            this.vertexMap = new Visualization.Selection.VertexMapBuilder(residueCount);
                        }
                        Object.defineProperty(CartoonsGeometryState.prototype, "verticesDone", {
                            get: function () {
                                return this.vs.elementCount;
                            },
                            enumerable: true,
                            configurable: true
                        });
                        Object.defineProperty(CartoonsGeometryState.prototype, "trianglesDone", {
                            get: function () {
                                return this.is.elementCount;
                            },
                            enumerable: true,
                            configurable: true
                        });
                        Object.defineProperty(CartoonsGeometryState.prototype, "directionConesBuilder", {
                            get: function () {
                                if (this.dConesInit)
                                    return this.dCones;
                                this.dConesInit = true;
                                this.dCones = GB.createDynamic(this.residueCount, this.residueCount);
                                return this.dCones;
                            },
                            enumerable: true,
                            configurable: true
                        });
                        CartoonsGeometryState.prototype.addVertex = function (v, n) {
                            GB.addVertex3d(this.builder, v.x, v.y, v.z);
                            GB.addNormal3d(this.builder, n.x, n.y, n.z);
                        };
                        CartoonsGeometryState.prototype.addTriangle = function (i, j, k) {
                            GB.addIndex3d(this.builder, i, j, k);
                        };
                        CartoonsGeometryState.prototype.addTriangles = function (i, j, k, u, v, w) {
                            GB.addIndex3d(this.builder, i, j, k);
                            GB.addIndex3d(this.builder, u, v, w);
                        };
                        return CartoonsGeometryState;
                    }());
                    Geometry.CartoonsGeometryState = CartoonsGeometryState;
                    function makeStrandLineTemplate(ctx) {
                        var radius = ctx.params.nucleotideStrandLineWidth, tessalation = ctx.params.tessalation;
                        var capPoints = 0, radiusPoints = 0, geom;
                        switch (tessalation) {
                            case 0:
                                radiusPoints = 2;
                                capPoints = 1;
                                break;
                            case 1:
                                radiusPoints = 3;
                                capPoints = 2;
                                break;
                            case 2:
                                radiusPoints = 4;
                                capPoints = 2;
                                break;
                            case 3:
                                radiusPoints = 8;
                                capPoints = 4;
                                break;
                            case 4:
                                radiusPoints = 10;
                                capPoints = 6;
                                break;
                            case 5:
                                radiusPoints = 14;
                                capPoints = 6;
                                break;
                            default:
                                radiusPoints = 16;
                                capPoints = 8;
                                break;
                        }
                        var arc = [], delta = (Math.PI / 2) / capPoints;
                        for (var i = 0; i <= capPoints; i++) {
                            arc[i] = new Visualization.THREE.Vector3(0, radius * Math.cos(i * delta), 0.1 * Math.sin(i * delta));
                            arc[i].z += 0.9;
                        }
                        geom = new Visualization.THREE.LatheGeometry([new Visualization.THREE.Vector3(0, radius, 0)].concat(arc), radiusPoints, Math.PI);
                        var templ = Visualization.GeometryHelper.getIndexedBufferGeometry(geom);
                        ctx.strandTemplate = {
                            vertex: templ.attributes.position.array,
                            normal: templ.attributes.normal.array,
                            index: templ.attributes.index.array,
                            geometry: templ
                        };
                    }
                    function buildUnit(unit, ctx) {
                        var state = ctx.state, params = ctx.params;
                        var builder = ctx.builder;
                        for (var index = 0, _max = unit.residueCount; index < _max; index++) {
                            state.vertexMap.startElement(unit.residueIndex[index]);
                            var numVertices = state.verticesDone;
                            state.residueIndex = index;
                            var start = unit.structureStarts.has(unit.residueIndex[index]);
                            var end = unit.structureEnds.has(unit.residueIndex[index]);
                            if (ctx.isTrace || unit.backboneOnly) {
                                switch (unit.residueType[index]) {
                                    case 5 /* Strand */:
                                        builder.addTube(unit, state, params.strandWidth, params.strandWidth, builder.hasP(unit.residueIndex[index], ctx.strandArrays) ? params.nucleotideStrandFactor : 1);
                                        if (start || end) {
                                            builder.addTubeCap(unit, state, params.strandWidth, params.strandWidth, start, end);
                                        }
                                        if (!ctx.strandTemplate) {
                                            makeStrandLineTemplate(ctx);
                                        }
                                        builder.addStrandLine(unit, state, ctx.strandTemplate, ctx.strandArrays, unit.residueIndex[index]);
                                        break;
                                    default:
                                        builder.addTube(unit, state, params.turnWidth, params.turnWidth, 1);
                                        if (start || end) {
                                            builder.addTubeCap(unit, state, params.turnWidth, params.turnWidth, start, end);
                                        }
                                        break;
                                }
                            }
                            else {
                                switch (unit.residueType[index]) {
                                    case 1 /* Helix */:
                                        builder.addTube(unit, state, params.helixWidth, params.helixHeight, 1);
                                        if (start) {
                                            builder.addTubeCap(unit, state, params.helixWidth, params.helixHeight, true, false);
                                        }
                                        else if (end) {
                                            builder.addTubeCap(unit, state, params.helixWidth, params.helixHeight, false, true);
                                        }
                                        break;
                                    case 3 /* Sheet */:
                                        builder.addSheet(unit, state, start, end);
                                        if (start || end) {
                                            builder.addSheetCap(unit, state, start, end);
                                        }
                                        break;
                                    case 5 /* Strand */:
                                        builder.addTube(unit, state, params.strandWidth, params.strandWidth, builder.hasP(unit.residueIndex[index], ctx.strandArrays) ? params.nucleotideStrandFactor : 1);
                                        if (start || end) {
                                            builder.addTubeCap(unit, state, params.strandWidth, params.strandWidth, start, end);
                                        }
                                        if (!ctx.strandTemplate) {
                                            makeStrandLineTemplate(ctx);
                                        }
                                        builder.addStrandLine(unit, state, ctx.strandTemplate, ctx.strandArrays, unit.residueIndex[index]);
                                        break;
                                    default:
                                        builder.addTube(unit, state, params.turnWidth, params.turnWidth, 1);
                                        if (start || end) {
                                            builder.addTubeCap(unit, state, params.turnWidth, params.turnWidth, start, end);
                                        }
                                        break;
                                }
                            }
                            if (ctx.parameters.showDirectionCones && unit.residueType[index] !== 5 /* Strand */) {
                                renderDirectionCone(ctx, unit, 2 * params.sheetHeight, index);
                            }
                            state.vertexMap.addVertexRange(numVertices, state.verticesDone);
                            state.vertexMap.endElement();
                        }
                    }
                    Geometry.buildUnit = buildUnit;
                    function isGap(ctx, a, b) {
                        var chainIndex = ctx.model.data.residues.chainIndex;
                        return chainIndex[a.endResidueIndex] === chainIndex[b.endResidueIndex];
                    }
                    var Vec3 = LiteMol.Core.Geometry.LinearAlgebra.Vector3;
                    var Mat4 = LiteMol.Core.Geometry.LinearAlgebra.Matrix4;
                    function renderGap(ctx, unitA, unitB) {
                        var aL = unitA.controlPoints.length;
                        var cpA = unitA.controlPoints, cpB = unitB.controlPoints;
                        var a = Vec3.fromValues(cpA[aL - 3], cpA[aL - 2], cpA[aL - 1]), b = Vec3.fromValues(cpB[0], cpB[1], cpB[2]);
                        var r = ctx.state.params.turnWidth / 2;
                        GB.addDashedLine(ctx.state.gapsBuilder, a, b, 0.5, 0.5, r);
                    }
                    var coneTemplate = (function () {
                        var geom = new Visualization.THREE.CylinderGeometry(0, 1, 1, 6, 1);
                        var ret = Visualization.GeometryHelper.toRawGeometry(geom);
                        geom.dispose();
                        return ret;
                    })();
                    var coneDirection = Vec3.zero(), coneUp = Vec3.fromValues(0, 1, 0), coneA = Vec3.zero(), coneB = Vec3.zero(), coneTranslation = Vec3.zero(), coneScale = Vec3.zero(), coneRotation = Mat4.identity();
                    function renderDirectionCone(ctx, unit, radius, residueIndex) {
                        if (unit.residueCount <= 2)
                            return;
                        var cp = unit.controlPoints;
                        var i = residueIndex * unit.linearSegmentCount + ((0.35 * unit.linearSegmentCount + 1) | 0);
                        var j = residueIndex * unit.linearSegmentCount + ((0.85 * unit.linearSegmentCount + 1) | 0);
                        if (i === j || 3 * j > cp.length)
                            return;
                        Vec3.set(coneTranslation, cp[3 * i], cp[3 * i + 1], cp[3 * i + 2]);
                        Vec3.set(coneA, cp[3 * i], cp[3 * i + 1], cp[3 * i + 2]);
                        Vec3.set(coneB, cp[3 * j], cp[3 * j + 1], cp[3 * j + 2]);
                        Vec3.sub(coneA, coneB, coneA);
                        var l = Vec3.magnitude(coneA);
                        if (l <= 0.1)
                            return;
                        Vec3.set(coneScale, 2 * radius, l, 2 * radius);
                        Vec3.normalize(coneA, coneA);
                        Vec3.makeRotation(coneRotation, coneUp, coneA);
                        GB.addRawTransformed(ctx.state.directionConesBuilder, coneTemplate, coneScale, coneTranslation, coneRotation);
                    }
                    function buildUnitsAsync(ctx) {
                        return __awaiter(this, void 0, void 0, function () {
                            var chunkSize, started, unitIndex, residuesDone, t, i;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        chunkSize = 10000;
                                        started = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        unitIndex = 0;
                                        _a.label = 1;
                                    case 1:
                                        if (!(unitIndex < ctx.units.length)) return [3 /*break*/, 4];
                                        residuesDone = 0;
                                        while (residuesDone < chunkSize && unitIndex < ctx.units.length) {
                                            buildUnit(ctx.units[unitIndex], ctx);
                                            residuesDone += ctx.units[unitIndex].residueCount;
                                            unitIndex++;
                                        }
                                        t = LiteMol.Core.Utils.PerformanceMonitor.currentTime();
                                        if (!(t - started > LiteMol.Core.Computation.UpdateProgressDelta)) return [3 /*break*/, 3];
                                        started = t;
                                        return [4 /*yield*/, ctx.computation.updateProgress('Building units...', true, unitIndex, ctx.units.length)];
                                    case 2:
                                        _a.sent();
                                        _a.label = 3;
                                    case 3: return [3 /*break*/, 1];
                                    case 4:
                                        for (i = 0; i < ctx.units.length - 1; i++) {
                                            if (isGap(ctx, ctx.units[i], ctx.units[i + 1])) {
                                                renderGap(ctx, ctx.units[i], ctx.units[i + 1]);
                                            }
                                        }
                                        return [2 /*return*/];
                                }
                            });
                        });
                    }
                    Geometry.buildUnitsAsync = buildUnitsAsync;
                    function createGeometry(ctx) {
                        var state = ctx.state;
                        var colorBuffer = new Float32Array(state.verticesDone * 3), pickColorBuffer = new Float32Array(state.verticesDone * 4), stateBuffer = new Float32Array(state.verticesDone);
                        var geometry = GB.toBufferGeometry(state.builder);
                        geometry.addAttribute('color', new Visualization.THREE.BufferAttribute(colorBuffer, 3));
                        ctx.geom.vertexStateBuffer = new Visualization.THREE.BufferAttribute(stateBuffer, 1);
                        geometry.addAttribute('vState', ctx.geom.vertexStateBuffer);
                        ctx.geom.geometry = geometry;
                        if (state.gapsBuilder.vertices.elementCount) {
                            ctx.geom.gapsGeometry = GB.toBufferGeometry(state.gapsBuilder);
                        }
                        if (state.directionConesBuilder.vertices.elementCount) {
                            ctx.geom.directionConesGeometry = GB.toBufferGeometry(state.directionConesBuilder);
                        }
                        var map = ctx.geom.vertexMap, color = { r: 0.45, g: 0.45, b: 0.45 }, vertexRanges = map.vertexRanges;
                        for (var _i = 0, _a = map.elementIndices; _i < _a.length; _i++) {
                            var elementIndex = _a[_i];
                            var elementOffset = map.elementMap.get(elementIndex);
                            var rangeStart = map.elementRanges[2 * elementOffset], rangeEnd = map.elementRanges[2 * elementOffset + 1];
                            if (rangeStart === rangeEnd)
                                continue;
                            Visualization.Selection.Picking.assignPickColor(elementIndex, color);
                            for (var i = rangeStart; i < rangeEnd; i += 2) {
                                var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                                for (var j = vStart; j < vEnd; j++) {
                                    pickColorBuffer[j * 4] = color.r;
                                    pickColorBuffer[j * 4 + 1] = color.g;
                                    pickColorBuffer[j * 4 + 2] = color.b;
                                }
                            }
                        }
                        var pickGeometry = new Visualization.THREE.BufferGeometry();
                        pickGeometry.addAttribute('position', geometry.getAttribute('position'));
                        pickGeometry.addAttribute('index', geometry.getAttribute('index'));
                        pickGeometry.addAttribute('pColor', new Visualization.THREE.BufferAttribute(pickColorBuffer, 4));
                        ctx.geom.pickGeometry = pickGeometry;
                    }
                    Geometry.createGeometry = createGeometry;
                    var Builder = /** @class */ (function () {
                        function Builder() {
                            this.tempVectors = [
                                new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(),
                                new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(),
                                new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3(), new Visualization.THREE.Vector3()
                            ];
                        }
                        Builder.prototype.setVector = function (data, i, v) {
                            v.set(data[3 * i], data[3 * i + 1], data[3 * i + 2]);
                            return v;
                        };
                        Builder.prototype.addTube = function (element, state, width, height, waveFactor) {
                            var verticesDone = state.verticesDone, i = 0, j = 0, radialVector = this.tempVectors[0], normalVector = this.tempVectors[1], tempPos = this.tempVectors[2], a = this.tempVectors[3], b = this.tempVectors[4], u = this.tempVectors[5], v = this.tempVectors[6], elementOffsetStart = state.residueIndex * element.linearSegmentCount, elementOffsetEnd = elementOffsetStart + element.linearSegmentCount, elementPoints = element.controlPoints, elementPointsCount = element.linearSegmentCount + 1, torsionVectors = element.torsionVectors, normalVectors = element.normalVectors, radialSegmentCount = state.params.radialSegmentCount;
                            var di = 1 / (elementOffsetEnd - elementOffsetStart);
                            for (i = elementOffsetStart; i <= elementOffsetEnd; i++) {
                                this.setVector(torsionVectors, i, u);
                                this.setVector(normalVectors, i, v);
                                var tt = di * (i - elementOffsetStart) - 0.5;
                                var ff = 1 + (waveFactor - 1) * (Math.cos(2 * Math.PI * tt) + 1);
                                var w = ff * width, h = ff * height;
                                for (j = 0; j < radialSegmentCount; j++) {
                                    var t = 2 * Math.PI * j / radialSegmentCount;
                                    a.copy(u);
                                    b.copy(v);
                                    radialVector.addVectors(a.multiplyScalar(w * Math.cos(t)), b.multiplyScalar(h * Math.sin(t)));
                                    a.copy(u);
                                    b.copy(v);
                                    normalVector.addVectors(a.multiplyScalar(h * Math.cos(t)), b.multiplyScalar(w * Math.sin(t)));
                                    normalVector.normalize();
                                    this.setVector(elementPoints, i, tempPos);
                                    tempPos.add(radialVector);
                                    state.addVertex(tempPos, normalVector);
                                }
                            }
                            for (i = 0; i < elementPointsCount - 1; i++) {
                                for (j = 0; j < radialSegmentCount; j++) {
                                    state.addTriangles((verticesDone + i * radialSegmentCount + j), (verticesDone + (i + 1) * radialSegmentCount + (j + 1) % radialSegmentCount), (verticesDone + i * radialSegmentCount + (j + 1) % radialSegmentCount), (verticesDone + i * radialSegmentCount + j), (verticesDone + (i + 1) * radialSegmentCount + j), (verticesDone + (i + 1) * radialSegmentCount + (j + 1) % radialSegmentCount));
                                }
                            }
                        };
                        Builder.prototype.addTubeCap = function (element, state, width, height, isStart, isEnd) {
                            var verticesDone = state.verticesDone, t, radialVector = this.tempVectors[0], normalVector = this.tempVectors[1], a = this.tempVectors[2], b = this.tempVectors[3], u = this.tempVectors[4], v = this.tempVectors[5], tA = this.tempVectors[6], tB = this.tempVectors[7], elementOffsetStart = state.residueIndex * element.linearSegmentCount, elementPoints = element.controlPoints, elementPointsCount = element.linearSegmentCount + 1, torsionVectors = element.torsionVectors, normalVectors = element.normalVectors, radialSegmentCount = state.params.radialSegmentCount;
                            this.setVector(torsionVectors, elementOffsetStart, tA);
                            this.setVector(normalVectors, elementOffsetStart, tB);
                            normalVector.crossVectors(tA, tB);
                            if (isEnd) {
                                normalVector.negate();
                            }
                            var offset = elementOffsetStart + (isStart ? 0 : (elementPointsCount - 1));
                            this.setVector(elementPoints, offset, radialVector);
                            state.addVertex(radialVector, normalVector);
                            this.setVector(torsionVectors, offset, u);
                            this.setVector(normalVectors, offset, v);
                            for (var i = 0; i < radialSegmentCount; i++) {
                                t = 2 * Math.PI * i / radialSegmentCount;
                                a.copy(u);
                                b.copy(v);
                                radialVector.addVectors(a.multiplyScalar(Math.cos(t) * width), b.multiplyScalar(Math.sin(t) * height));
                                this.setVector(elementPoints, offset, tA);
                                radialVector.add(tA);
                                state.addVertex(radialVector, normalVector);
                                if (isStart) {
                                    state.addTriangle(verticesDone, (verticesDone + i + 1), (verticesDone + (i + 1) % radialSegmentCount + 1));
                                }
                                else {
                                    state.addTriangle((verticesDone), (verticesDone + (i + 1) % radialSegmentCount + 1), (verticesDone + i + 1));
                                }
                            }
                        };
                        Builder.prototype.addSheet = function (element, state, isStart, isEnd) {
                            var verticesDone = state.verticesDone, params = state.params, i = 0, j = 0, horizontalVector = this.tempVectors[0], verticalVector = this.tempVectors[1], positionVector = this.tempVectors[2], normalOffset = this.tempVectors[3], normalVector = this.tempVectors[4], temp = this.tempVectors[5], tA = this.tempVectors[7], tB = this.tempVectors[8], torsionVector = this.tempVectors[9], elementOffsetStart = state.residueIndex * element.linearSegmentCount, elementOffsetEnd = elementOffsetStart + element.linearSegmentCount, elementPoints = element.controlPoints, torsionVectors = element.torsionVectors, normalVectors = element.normalVectors, offsetLength = 0, actualWidth = 0;
                            normalOffset.set(0, 0, 0);
                            if (isEnd) {
                                this.setVector(elementPoints, elementOffsetEnd, tA);
                                this.setVector(elementPoints, elementOffsetStart, tB);
                                offsetLength = params.arrowWidth / temp.subVectors(tA, tB).length();
                            }
                            for (i = elementOffsetStart; i <= elementOffsetEnd; i++) {
                                actualWidth = !isEnd ? params.sheetWidth : params.arrowWidth * (1 - (i - elementOffsetStart) / element.linearSegmentCount);
                                this.setVector(torsionVectors, i, horizontalVector);
                                horizontalVector.multiplyScalar(actualWidth);
                                this.setVector(normalVectors, i, verticalVector);
                                verticalVector.multiplyScalar(params.sheetHeight);
                                if (isEnd) {
                                    this.setVector(normalVectors, i, tA);
                                    this.setVector(torsionVectors, i, tB);
                                    normalOffset.crossVectors(tA, tB).multiplyScalar(offsetLength);
                                }
                                this.setVector(elementPoints, i, positionVector);
                                this.setVector(normalVectors, i, normalVector);
                                this.setVector(torsionVectors, i, torsionVector);
                                tA.copy(positionVector).add(horizontalVector).add(verticalVector);
                                tB.copy(normalVector);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).sub(horizontalVector).add(verticalVector);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).sub(horizontalVector).add(verticalVector);
                                tB.copy(torsionVector).negate().add(normalOffset);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).sub(horizontalVector).sub(verticalVector);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).sub(horizontalVector).sub(verticalVector);
                                tB.copy(normalVector).negate();
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).add(horizontalVector).sub(verticalVector);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).add(horizontalVector).sub(verticalVector);
                                tB.copy(torsionVector).add(normalOffset);
                                state.addVertex(tA, tB);
                                tA.copy(positionVector).add(horizontalVector).add(verticalVector);
                                state.addVertex(tA, tB);
                            }
                            for (i = 0; i < element.linearSegmentCount; i++) {
                                for (j = 0; j < 4; j++) {
                                    state.addTriangles(verticesDone + i * 8 + 2 * j, verticesDone + (i + 1) * 8 + 2 * j + 1, verticesDone + i * 8 + 2 * j + 1, verticesDone + i * 8 + 2 * j, verticesDone + (i + 1) * 8 + 2 * j, verticesDone + (i + 1) * 8 + 2 * j + 1);
                                }
                            }
                        };
                        Builder.prototype.addSheetCap = function (element, state, isStart, isEnd) {
                            var params = state.params, elementOffsetStart = state.residueIndex * element.linearSegmentCount, elementPoint = this.setVector(element.controlPoints, elementOffsetStart, this.tempVectors[0]);
                            var horizontalVector = this.setVector(element.torsionVectors, elementOffsetStart, this.tempVectors[1]).multiplyScalar(params.sheetWidth);
                            var verticalVector = this.setVector(element.normalVectors, elementOffsetStart, this.tempVectors[2]).multiplyScalar(params.sheetHeight);
                            var p1 = this.tempVectors[3].addVectors(elementPoint, horizontalVector).add(verticalVector), p2 = this.tempVectors[4].subVectors(elementPoint, horizontalVector).add(verticalVector), p3 = this.tempVectors[5].subVectors(elementPoint, horizontalVector).sub(verticalVector), p4 = this.tempVectors[6].addVectors(elementPoint, horizontalVector).sub(verticalVector);
                            if (isStart) {
                                this.addSheepCapSection(state, p1, p2, p3, p4);
                            }
                            else {
                                var arrowHorizontalVector = this.setVector(element.torsionVectors, elementOffsetStart, this.tempVectors[7]).multiplyScalar(params.arrowWidth);
                                var p5 = this.tempVectors[8].addVectors(elementPoint, arrowHorizontalVector).add(verticalVector), p6 = this.tempVectors[9].subVectors(elementPoint, arrowHorizontalVector).add(verticalVector), p7 = this.tempVectors[10].subVectors(elementPoint, arrowHorizontalVector).sub(verticalVector), p8 = this.tempVectors[11].addVectors(elementPoint, arrowHorizontalVector).sub(verticalVector);
                                this.addSheepCapSection(state, p5, p1, p4, p8);
                                this.addSheepCapSection(state, p2, p6, p7, p3);
                            }
                        };
                        Builder.prototype.addSheepCapSection = function (state, p1, p2, p3, p4) {
                            var addedVerticesCount = state.verticesDone, normal = this.tempVectors[12].crossVectors(this.tempVectors[13].subVectors(p2, p1), this.tempVectors[14].subVectors(p4, p1)).normalize();
                            state.addVertex(p1, normal);
                            state.addVertex(p2, normal);
                            state.addVertex(p3, normal);
                            state.addVertex(p4, normal);
                            state.addTriangles(addedVerticesCount, addedVerticesCount + 1, addedVerticesCount + 2, addedVerticesCount + 2, addedVerticesCount + 3, addedVerticesCount);
                        };
                        Builder.prototype.findN3 = function (index, arrays, target) {
                            var start = arrays.startIndex[index], end = arrays.endIndex[index];
                            var found = false;
                            for (var i = start; i < end; i++) {
                                if (arrays.name[i] === "N3") {
                                    target.set(arrays.x[i], arrays.y[i], arrays.z[i]);
                                    found = true;
                                    break;
                                }
                            }
                            return found;
                        };
                        Builder.prototype.hasP = function (index, arrays) {
                            var start = arrays.startIndex[index], end = arrays.endIndex[index];
                            for (var i = start; i < end; i++) {
                                if (arrays.name[i] === "P")
                                    return true;
                            }
                            return false;
                        };
                        Builder.prototype.addStrandLine = function (element, state, template, arrays, residueIndex) {
                            if (!this.findN3(residueIndex, arrays, this.tempVectors[3]))
                                return;
                            var p = this.tempVectors[0], n = this.tempVectors[1], i, vb = template.vertex, nb = template.normal, ib = template.index, vertexStart = state.verticesDone, vertexCount = vb.length, triangleCount = ib.length, elementOffset = state.residueIndex * element.linearSegmentCount + ((0.5 * element.linearSegmentCount + 1) | 0), elementPoint = this.setVector(element.controlPoints, elementOffset, this.tempVectors[2]), nDir = this.tempVectors[3].sub(elementPoint), length = nDir.length();
                            nDir.normalize();
                            state.translationMatrix.makeTranslation(elementPoint.x, elementPoint.y, elementPoint.z);
                            state.scaleMatrix.makeScale(1, 1, length);
                            state.rotationMatrix.makeRotationAxis(new Visualization.THREE.Vector3(-nDir.y, nDir.x, 0), Math.acos(nDir.z));
                            state.translationMatrix.multiply(state.rotationMatrix).multiply(state.scaleMatrix);
                            template.geometry.applyMatrix(state.translationMatrix);
                            for (i = 0; i < vertexCount; i += 3) {
                                p.set(vb[i], vb[i + 1], vb[i + 2]);
                                n.set(nb[i], nb[i + 1], nb[i + 2]);
                                state.addVertex(p, n);
                            }
                            for (i = 0; i < triangleCount; i += 3) {
                                state.addTriangle(vertexStart + ib[i], vertexStart + ib[i + 1], vertexStart + ib[i + 2]);
                            }
                            state.invMatrix.getInverse(state.translationMatrix);
                            template.geometry.applyMatrix(state.invMatrix);
                        };
                        return Builder;
                    }());
                    Geometry.Builder = Builder;
                })(Geometry = Cartoons.Geometry || (Cartoons.Geometry = {}));
            })(Cartoons = Molecule.Cartoons || (Molecule.Cartoons = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var Cartoons;
            (function (Cartoons) {
                "use strict";
                var CartoonsModelType;
                (function (CartoonsModelType) {
                    CartoonsModelType[CartoonsModelType["Default"] = 0] = "Default";
                    CartoonsModelType[CartoonsModelType["AlphaTrace"] = 1] = "AlphaTrace";
                })(CartoonsModelType = Cartoons.CartoonsModelType || (Cartoons.CartoonsModelType = {}));
                ;
                Cartoons.DefaultCartoonsModelParameters = {
                    tessalation: 3,
                    drawingType: CartoonsModelType.Default,
                    showDirectionCones: true
                };
                var Model = /** @class */ (function (_super) {
                    __extends(Model, _super);
                    function Model() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Model.prototype.applySelectionInternal = function (indices, action) {
                        var buffer = this.cartoons.vertexStateBuffer, array = buffer.array, map = this.cartoons.vertexMap, vertexRanges = map.vertexRanges, changed = false, residueIndex = this.model.data.atoms.residueIndex;
                        for (var a = 0, _a = indices.length; a < _a; a++) {
                            var index = residueIndex[indices[a]];
                            a++;
                            while (residueIndex[indices[a]] === index) {
                                a++;
                            }
                            a--;
                            if (!map.elementMap.has(index))
                                continue;
                            var indexOffset = map.elementMap.get(index), rangeStart = map.elementRanges[2 * indexOffset], rangeEnd = map.elementRanges[2 * indexOffset + 1];
                            if (rangeStart === rangeEnd)
                                continue;
                            for (var i = rangeStart; i < rangeEnd; i += 2) {
                                var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                                changed = Visualization.Selection.applyActionToRange(array, vStart, vEnd, action) || changed;
                            }
                        }
                        if (!changed)
                            return false;
                        buffer.needsUpdate = true;
                        return true;
                    };
                    Model.prototype.getPickElements = function (pickId) {
                        var _c = this.model.data.residues, atomStartIndex = _c.atomStartIndex, atomEndIndex = _c.atomEndIndex;
                        var elements = [];
                        for (var i = atomStartIndex[pickId], _b = atomEndIndex[pickId]; i < _b; i++) {
                            if (this.queryContext.hasAtom(i))
                                elements.push(i);
                        }
                        return elements;
                    };
                    Model.prototype.highlightElement = function (pickId, highlight) {
                        return this.applySelection([this.model.data.residues.atomStartIndex[pickId]], highlight ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                    };
                    Model.prototype.highlightInternal = function (isOn) {
                        return Visualization.Selection.applyActionToBuffer(this.cartoons.vertexStateBuffer, isOn ? 3 /* Highlight */ : 4 /* RemoveHighlight */);
                    };
                    Model.prototype.applyColoring = function (theme) {
                        var _c = this.model.data.residues, atomStartIndex = _c.atomStartIndex, atomEndIndex = _c.atomEndIndex;
                        var color = { r: 0.1, g: 0.1, b: 0.1 };
                        var avgColor = { r: 0.1, g: 0.1, b: 0.1 };
                        var map = this.cartoons.vertexMap;
                        var bufferAttribute = this.cartoons.geometry.attributes.color;
                        var buffer = bufferAttribute.array;
                        var vertexRanges = map.vertexRanges;
                        for (var rI = 0, _bRi = this.model.data.residues.count; rI < _bRi; rI++) {
                            avgColor.r = 0;
                            avgColor.g = 0;
                            avgColor.b = 0;
                            var count = 0;
                            for (var aI = atomStartIndex[rI], _bAi = atomEndIndex[rI]; aI < _bAi; aI++) {
                                if (!this.queryContext.hasAtom(aI))
                                    continue;
                                theme.setElementColor(aI, color);
                                avgColor.r += color.r;
                                avgColor.g += color.g;
                                avgColor.b += color.b;
                                count++;
                            }
                            if (!count)
                                continue;
                            color.r = avgColor.r / count;
                            color.g = avgColor.g / count;
                            color.b = avgColor.b / count;
                            var elementOffset = map.elementMap.get(rI);
                            var rangeStart = map.elementRanges[2 * elementOffset], rangeEnd = map.elementRanges[2 * elementOffset + 1];
                            if (rangeStart === rangeEnd)
                                continue;
                            for (var i = rangeStart; i < rangeEnd; i += 2) {
                                var vStart = vertexRanges[i], vEnd = vertexRanges[i + 1];
                                for (var j = vStart; j < vEnd; j++) {
                                    buffer[j * 3] = color.r,
                                        buffer[j * 3 + 1] = color.g,
                                        buffer[j * 3 + 2] = color.b;
                                }
                            }
                        }
                        bufferAttribute.needsUpdate = true;
                        // const gapColor = Theme.getColor(theme, 'Gap', Colors.DefaultBondColor);
                        // const gc = this.gapMaterial.color;
                        // if (gapColor.r !== gc.r || gapColor.g !== gc.g || gapColor.b !== gc.b) {
                        //     this.gapMaterial.color = new THREE.Color(gapColor.r, gapColor.g, gapColor.b);
                        //     this.gapMaterial.needsUpdate = true;
                        // }
                        // const dcColor = Theme.getColor(theme, 'DirectionCone', Colors.DefaultCartoonDirectionConeColor);
                        // const dc = this.gapMaterial.color;
                        // if (dcColor.r !== dc.r || dcColor.g !== dc.g || dcColor.b !== dc.b) {
                        //     this.directionConeMaterial.color = new THREE.Color(dcColor.r, dcColor.g, dcColor.b);
                        //     this.directionConeMaterial.needsUpdate = true;
                        // }
                    };
                    Model.prototype.applyThemeInternal = function (theme) {
                        this.applyColoring(theme);
                        Visualization.MaterialsHelper.updateMaterial(this.material, theme, this.object);
                        Visualization.MaterialsHelper.updateMaterial(this.gapMaterial, theme, this.object);
                        Visualization.MaterialsHelper.updateMaterial(this.directionConeMaterial, theme, this.object);
                    };
                    Model.prototype.createObjects = function () {
                        var main = new Visualization.THREE.Object3D();
                        main.add(new Visualization.THREE.Mesh(this.cartoons.geometry, this.material));
                        if (this.cartoons.gapsGeometry) {
                            main.add(new Visualization.THREE.Mesh(this.cartoons.gapsGeometry, this.gapMaterial));
                        }
                        if (this.cartoons.directionConesGeometry) {
                            main.add(new Visualization.THREE.Mesh(this.cartoons.directionConesGeometry, this.directionConeMaterial));
                        }
                        return {
                            main: main.children.length > 1 ? main : main.children[0],
                            pick: new Visualization.THREE.Mesh(this.cartoons.pickGeometry, this.pickMaterial)
                        };
                    };
                    Model.create = function (entity, _c) {
                        var _this = this;
                        var model = _c.model, queryContext = _c.queryContext, atomIndices = _c.atomIndices, theme = _c.theme, params = _c.params, props = _c.props;
                        return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var linearSegments, radialSements, cartoons, ret, obj;
                            return __generator(this, function (_c) {
                                switch (_c.label) {
                                    case 0:
                                        linearSegments = 0, radialSements = 0;
                                        return [4 /*yield*/, ctx.updateProgress('Computing cartoons...')];
                                    case 1:
                                        _c.sent();
                                        params = LiteMol.Core.Utils.extend({}, params, Cartoons.DefaultCartoonsModelParameters);
                                        switch (params.tessalation) {
                                            case 0:
                                                linearSegments = 2;
                                                radialSements = 2;
                                                break;
                                            case 1:
                                                linearSegments = 4;
                                                radialSements = 3;
                                                break;
                                            case 2:
                                                linearSegments = 6;
                                                radialSements = 5;
                                                break;
                                            case 3:
                                                linearSegments = 10;
                                                radialSements = 8;
                                                break;
                                            case 4:
                                                linearSegments = 12;
                                                radialSements = 10;
                                                break;
                                            case 5:
                                                linearSegments = 16;
                                                radialSements = 14;
                                                break;
                                            default:
                                                linearSegments = 18;
                                                radialSements = 16;
                                                break;
                                        }
                                        return [4 /*yield*/, Cartoons.Geometry.create(model, atomIndices, linearSegments, {
                                                radialSegmentCount: radialSements,
                                                tessalation: +params.tessalation,
                                                showDirectionCones: !!params.showDirectionCones
                                            }, params.drawingType === CartoonsModelType.AlphaTrace, ctx)];
                                    case 2:
                                        cartoons = _c.sent();
                                        ret = new Model();
                                        ret.cartoons = cartoons;
                                        ret.queryContext = queryContext;
                                        ret.material = Visualization.MaterialsHelper.getMeshMaterial();
                                        ret.gapMaterial = new Visualization.THREE.MeshPhongMaterial({ color: 0x777777, shading: Visualization.THREE.FlatShading });
                                        ret.directionConeMaterial = new Visualization.THREE.MeshPhongMaterial({ color: 0x999999, shading: Visualization.THREE.FlatShading });
                                        ret.pickMaterial = Visualization.MaterialsHelper.getPickMaterial();
                                        if (props)
                                            ret.props = props;
                                        ret.entity = entity;
                                        ret.cartoons.geometry.computeBoundingSphere();
                                        ret.centroid = ret.cartoons.geometry.boundingSphere.center;
                                        ret.radius = ret.cartoons.geometry.boundingSphere.radius;
                                        obj = ret.createObjects();
                                        ret.object = obj.main;
                                        ret.pickObject = obj.pick;
                                        ret.pickBufferAttributes = [ret.cartoons.pickGeometry.attributes.pColor];
                                        ret.model = model;
                                        ret.applyTheme(theme);
                                        ret.disposeList.push(ret.cartoons, ret.material, ret.pickMaterial, ret.gapMaterial, ret.directionConeMaterial);
                                        return [2 /*return*/, ret];
                                }
                            });
                        }); });
                    };
                    return Model;
                }(Visualization.Model));
                Cartoons.Model = Model;
            })(Cartoons = Molecule.Cartoons || (Molecule.Cartoons = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Molecule;
        (function (Molecule) {
            var Colors;
            (function (Colors) {
                Colors.DefaultBondColor = { r: 0.6, g: 0.6, b: 0.6 };
                Colors.DefaultCartoonDirectionConeColor = { r: 0.85, g: 0.85, b: 0.85 };
                Colors.DefaultElementColor = { r: 0.6, g: 0.6, b: 0.6 };
                Colors.DefaultElementColorMap = LiteMol.Core.Utils.FastMap.create();
                Colors.DefaultPallete = [];
                (function () {
                    var colors = [["Ac", 0.43921, 0.67058, 0.98039], ["Al", 0.74901, 0.65098, 0.65098], ["Am", 0.32941, 0.36078, 0.94901], ["Sb", 0.6196, 0.38823, 0.7098], ["Ar", 0.50196, 0.8196, 0.89019], ["As", 0.74117, 0.50196, 0.89019], ["At", 0.45882, 0.3098, 0.27058], ["Ba", 0, 0.78823, 0], ["Bk", 0.54117, 0.3098, 0.89019], ["Be", 0.76078, 1, 0], ["Bi", 0.6196, 0.3098, 0.7098], ["Bh", 0.87843, 0, 0.2196], ["B", 1, 0.7098, 0.7098], ["Br", 0.65098, 0.16078, 0.16078], ["Cd", 1, 0.85098, 0.56078], ["Ca", 0.23921, 1, 0], ["Cf", 0.63137, 0.21176, 0.83137], ["C", 0.45, 0.45, 0.45], ["Ce", 1, 1, 0.78039], ["Cs", 0.34117, 0.09019, 0.56078], ["Cl", 0.12156, 0.94117, 0.12156], ["Cr", 0.54117, 0.6, 0.78039], ["Co", 0.94117, 0.5647, 0.62745], ["Cu", 0.78431, 0.50196, 0.2], ["Cm", 0.47058, 0.36078, 0.89019], ["D", 0.9, 0.9, 0.9], ["Db", 0.8196, 0, 0.3098], ["Dy", 0.12156, 1, 0.78039], ["Es", 0.70196, 0.12156, 0.83137], ["Er", 0, 0.90196, 0.45882], ["Eu", 0.38039, 1, 0.78039], ["Fm", 0.70196, 0.12156, 0.72941], ["F", 0.70196, 1, 1], ["Fr", 0.25882, 0, 0.4], ["Gd", 0.27058, 1, 0.78039], ["Ga", 0.76078, 0.56078, 0.56078], ["Ge", 0.4, 0.56078, 0.56078], ["Au", 1, 0.8196, 0.13725], ["Hf", 0.30196, 0.76078, 1], ["Hs", 0.90196, 0, 0.18039], ["He", 0.85098, 1, 1], ["Ho", 0, 1, 0.61176], ["H", 0.9, 0.9, 0.9], ["In", 0.65098, 0.45882, 0.45098], ["I", 0.58039, 0, 0.58039], ["Ir", 0.09019, 0.32941, 0.52941], ["Fe", 0.698, 0.13, 0.13], ["Kr", 0.36078, 0.72156, 0.8196], ["La", 0.43921, 0.83137, 1], ["Lr", 0.78039, 0, 0.4], ["Pb", 0.34117, 0.34901, 0.38039], ["Li", 0.8, 0.50196, 1], ["Lu", 0, 0.67058, 0.14117], ["Mg", 0.54117, 1, 0], ["Mn", 0.61176, 0.47843, 0.78039], ["Mt", 0.92156, 0, 0.14901], ["Md", 0.70196, 0.05098, 0.65098], ["Hg", 0.72156, 0.72156, 0.81568], ["Mo", 0.32941, 0.7098, 0.7098], ["Nd", 0.78039, 1, 0.78039], ["Ne", 0.70196, 0.89019, 0.96078], ["Np", 0, 0.50196, 1], ["Ni", 0.31372, 0.81568, 0.31372], ["Nb", 0.45098, 0.76078, 0.78823], ["N", 0, 0.5, 1], ["No", 0.74117, 0.05098, 0.52941], ["Os", 0.14901, 0.4, 0.58823], ["O", 1, 0.3, 0.3], ["Pd", 0, 0.41176, 0.52156], ["P", 1, 0.50196, 0], ["Pt", 0.81568, 0.81568, 0.87843], ["Pu", 0, 0.4196, 1], ["Po", 0.67058, 0.36078, 0], ["K", 0.56078, 0.25098, 0.83137], ["Pr", 0.85098, 1, 0.78039], ["Pm", 0.63921, 1, 0.78039], ["Pa", 0, 0.63137, 1], ["Ra", 0, 0.49019, 0], ["Rn", 0.25882, 0.5098, 0.58823], ["Re", 0.14901, 0.49019, 0.67058], ["Rh", 0.03921, 0.49019, 0.54901], ["Rb", 0.43921, 0.18039, 0.69019], ["Ru", 0.14117, 0.56078, 0.56078], ["Rf", 0.8, 0, 0.34901], ["Sm", 0.56078, 1, 0.78039], ["Sc", 0.90196, 0.90196, 0.90196], ["Sg", 0.85098, 0, 0.27058], ["Se", 1, 0.63137, 0], ["Si", 0.94117, 0.78431, 0.62745], ["Ag", 0.75294, 0.75294, 0.75294], ["Na", 0.67058, 0.36078, 0.94901], ["Sr", 0, 1, 0], ["S", 0.9, 0.775, 0.25], ["Ta", 0.30196, 0.65098, 1], ["Tc", 0.23137, 0.6196, 0.6196], ["Te", 0.83137, 0.47843, 0], ["Tb", 0.18823, 1, 0.78039], ["Tl", 0.65098, 0.32941, 0.30196], ["Th", 0, 0.72941, 1], ["Tm", 0, 0.83137, 0.32156], ["Sn", 0.4, 0.50196, 0.50196], ["Ti", 0.74901, 0.76078, 0.78039], ["W", 0.12941, 0.58039, 0.83921], ["U", 0, 0.56078, 1], ["V", 0.65098, 0.65098, 0.67058], ["Xe", 0.25882, 0.6196, 0.69019], ["Yb", 0, 0.74901, 0.2196], ["Y", 0.58039, 1, 1], ["Zn", 0.49019, 0.50196, 0.69019], ["Zr", 0.58039, 0.87843, 0.87843]];
                    for (var _i = 0, colors_1 = colors; _i < colors_1.length; _i++) {
                        var c = colors_1[_i];
                        var n = c[0];
                        var clr = { r: c[1], g: c[2], b: c[3] };
                        Colors.DefaultElementColorMap.set(n, clr);
                        Colors.DefaultElementColorMap.set(n.toUpperCase(), clr);
                        Colors.DefaultElementColorMap.set(n.toLowerCase(), clr);
                        Colors.DefaultPallete.push(clr);
                    }
                })();
            })(Colors = Molecule.Colors || (Molecule.Colors = {}));
        })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Primitive;
        (function (Primitive) {
            "use strict";
            var LA = LiteMol.Core.Geometry.LinearAlgebra;
            function createSphereSurface(sphere) {
                var _a = sphere.tessalation, tessalation = _a === void 0 ? 0 : _a;
                var geom = new Visualization.THREE.IcosahedronGeometry(1.0, tessalation);
                var surf = Visualization.GeometryHelper.toSurface(geom);
                geom.dispose();
                return surf;
            }
            Primitive.createSphereSurface = createSphereSurface;
            function createTubeSurface(tube) {
                var a = tube.a, b = tube.b, _a = tube.slices, slices = _a === void 0 ? 12 : _a;
                var geom = new Visualization.THREE.TubeGeometry(new Visualization.THREE.LineCurve3(new Visualization.THREE.Vector3(a[0], a[1], a[2]), new Visualization.THREE.Vector3(b[0], b[1], b[2])), 2, tube.radius, slices);
                var surf = Visualization.GeometryHelper.toSurface(geom);
                geom.dispose();
                return surf;
            }
            Primitive.createTubeSurface = createTubeSurface;
            var coneAxis = [0, 1, 0], coneTransformRotation = LA.Matrix4.zero(), coneTransformTranslation = LA.Matrix4.zero(), coneTransformTranslation1 = LA.Matrix4.zero();
            function createCone(cone) {
                var a = cone.a, b = cone.b, radius = cone.radius, _a = cone.slices, slices = _a === void 0 ? 12 : _a;
                var height = LA.Vector3.distance(a, b);
                var geom = new Visualization.THREE.CylinderGeometry(0, radius, height, slices, 1);
                var surf = Visualization.GeometryHelper.toSurface(geom);
                geom.dispose();
                var dir = LA.Vector3.sub(b, b, a);
                LA.Vector3.makeRotation(coneTransformRotation, coneAxis, dir);
                LA.Matrix4.fromTranslation(coneTransformTranslation1, [0, height / 2, 0]);
                LA.Matrix4.fromTranslation(coneTransformTranslation, a);
                LiteMol.Core.Geometry.Surface.transformImmediate(surf, LA.Matrix4.mul3(coneTransformTranslation, coneTransformTranslation, coneTransformRotation, coneTransformTranslation1));
                LiteMol.Core.Geometry.Surface.computeNormalsImmediate(surf);
                return surf;
            }
            Primitive.createCone = createCone;
            function createArrow(arrow) {
                var id = arrow.id, a = arrow.a, b = arrow.b, radius = arrow.radius, _a = arrow.slices, slices = _a === void 0 ? 12 : _a, coneHeight = arrow.coneHeight, coneRadius = arrow.coneRadius;
                var len = LA.Vector3.distance(a, b);
                var t = len - coneHeight;
                var dir = LA.Vector3.normalize(b, LA.Vector3.sub(b, b, a));
                var pivot = [a[0] + t * dir[0], a[1] + t * dir[1], a[2] + t * dir[2]];
                return [
                    { type: 'Cone', a: pivot, b: b, id: id, radius: coneRadius, slices: slices },
                    { type: 'Tube', a: a, b: pivot, id: id, radius: radius, slices: slices }
                ];
            }
            Primitive.createArrow = createArrow;
            var dashSurface = (function () {
                var dash = Visualization.GeometryHelper.toSurface(new Visualization.THREE.BoxGeometry(1, 1, 1));
                for (var i = 0; i < dash.vertices.length; i += 3) {
                    dash.vertices[i + 2] += 0.5;
                }
                return dash;
            })();
            function createDashes(line) {
                var id = line.id, a = line.a, b = line.b, width = line.width, dashSize = line.dashSize, spaceSize = line.spaceSize;
                var length = LA.Vector3.distance(a, b);
                if (length === 0)
                    return [];
                var delta = dashSize + (spaceSize !== void 0 ? spaceSize : dashSize);
                var dir = LA.Vector3.sub(LA.Vector3(), b, a);
                LA.Vector3.normalize(dir, dir);
                var scale = LA.Vector3.fromValues(width, width, dashSize);
                var up = LA.Vector3.fromValues(0, 0, 1);
                var rotation = LA.Vector3.makeRotation(LA.Matrix4(), up, dir);
                var surfaces = [];
                LA.Vector3.scale(dir, dir, delta);
                var axis = LA.Vector3.copy(LA.Vector3(), a);
                for (var t = 0; t < length; t += delta) {
                    if (t + dashSize > length)
                        scale = LA.Vector3.fromValues(width, width, length - t);
                    surfaces.push({
                        type: 'Surface',
                        id: id,
                        surface: dashSurface,
                        rotation: rotation,
                        scale: scale,
                        translation: LA.Vector3.clone(axis)
                    });
                    LA.Vector3.add(axis, axis, dir);
                }
                return surfaces;
            }
            Primitive.createDashes = createDashes;
        })(Primitive = Visualization.Primitive || (Visualization.Primitive = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Visualization;
    (function (Visualization) {
        var Primitive;
        (function (Primitive) {
            'use strict';
            var LA = LiteMol.Core.Geometry.LinearAlgebra;
            var Surface = LiteMol.Core.Geometry.Surface;
            function buildSurface(shapes) {
                var _this = this;
                return LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                    var uniqueSpheres, shapeSurfaces, _i, shapes_1, s, sphere, tube, size, _a, shapeSurfaces_1, s, vertices, normals, triangles, annotation, vOffset, nOffset, tOffset, aOffset, v, scaleTransform, translateTransform, rotateTransform, transform, vs, shapeIndex, _c, shapes_2, s, surface, startVOffset, i, _b, ns, i, _b, i, _b, ns, i, _b, i, _b, ns, i, _b, i, _b, ns, i, _b, ts, i, _b, i, _b, ret;
                    return __generator(this, function (_d) {
                        switch (_d.label) {
                            case 0: return [4 /*yield*/, ctx.updateProgress('Building surface...')];
                            case 1:
                                _d.sent();
                                uniqueSpheres = LiteMol.Core.Utils.FastMap.create();
                                shapeSurfaces = [];
                                for (_i = 0, shapes_1 = shapes; _i < shapes_1.length; _i++) {
                                    s = shapes_1[_i];
                                    switch (s.type) {
                                        case 'Sphere':
                                            if (uniqueSpheres.has(s.tessalation || 0))
                                                shapeSurfaces.push(uniqueSpheres.get(s.tessalation || 0));
                                            else {
                                                sphere = Primitive.createSphereSurface(s);
                                                uniqueSpheres.set(s.tessalation || 0, sphere);
                                                shapeSurfaces.push(sphere);
                                            }
                                            break;
                                        case 'Tube': {
                                            tube = Primitive.createTubeSurface(s);
                                            shapeSurfaces.push(tube);
                                            break;
                                        }
                                        case 'Cone': {
                                            shapeSurfaces.push(Primitive.createCone(s));
                                            break;
                                        }
                                        case 'Surface': {
                                            shapeSurfaces.push(s.surface);
                                            break;
                                        }
                                    }
                                }
                                size = { vertexCount: 0, triangleCount: 0 };
                                for (_a = 0, shapeSurfaces_1 = shapeSurfaces; _a < shapeSurfaces_1.length; _a++) {
                                    s = shapeSurfaces_1[_a];
                                    size.vertexCount += s.vertexCount;
                                    size.triangleCount += s.triangleCount;
                                }
                                vertices = new Float32Array(size.vertexCount * 3);
                                normals = new Float32Array(size.vertexCount * 3);
                                triangles = new Uint32Array(size.triangleCount * 3);
                                annotation = new Int32Array(size.vertexCount);
                                vOffset = 0, nOffset = 0, tOffset = 0, aOffset = 0;
                                v = LA.Vector3.zero();
                                scaleTransform = LA.Matrix4.zero(), translateTransform = LA.Matrix4.zero(), rotateTransform = LA.Matrix4.zero(), transform = LA.Matrix4.zero();
                                shapeIndex = 0;
                                for (_c = 0, shapes_2 = shapes; _c < shapes_2.length; _c++) {
                                    s = shapes_2[_c];
                                    surface = shapeSurfaces[shapeIndex++];
                                    startVOffset = (vOffset / 3) | 0;
                                    switch (s.type) {
                                        case 'Sphere': {
                                            vs = surface.vertices;
                                            LA.Matrix4.fromScaling(scaleTransform, [s.radius, s.radius, s.radius]);
                                            LA.Matrix4.fromTranslation(translateTransform, s.center);
                                            LA.Matrix4.mul(transform, translateTransform, scaleTransform);
                                            for (i = 0, _b = surface.vertexCount * 3; i < _b; i += 3) {
                                                v[0] = vs[i], v[1] = vs[i + 1], v[2] = vs[i + 2];
                                                LA.Vector3.transformMat4(v, v, transform);
                                                vertices[vOffset++] = v[0];
                                                vertices[vOffset++] = v[1];
                                                vertices[vOffset++] = v[2];
                                            }
                                            ns = surface.normals;
                                            for (i = 0, _b = ns.length; i < _b; i++) {
                                                normals[nOffset++] = ns[i];
                                            }
                                            break;
                                        }
                                        case 'Tube':
                                        case 'Cone': {
                                            vs = surface.vertices;
                                            for (i = 0, _b = vs.length; i < _b; i++) {
                                                vertices[vOffset++] = vs[i];
                                            }
                                            ns = surface.normals;
                                            for (i = 0, _b = ns.length; i < _b; i++) {
                                                normals[nOffset++] = ns[i];
                                            }
                                            break;
                                        }
                                        case 'Surface': {
                                            if (!surface.normals)
                                                Surface.computeNormalsImmediate(surface);
                                            vs = surface.vertices;
                                            if (s.rotation || s.scale || s.translation) {
                                                LA.Matrix4.fromScaling(scaleTransform, s.scale || [1, 1, 1]);
                                                LA.Matrix4.fromTranslation(translateTransform, s.translation || [0, 0, 0]);
                                                if (s.rotation)
                                                    LA.Matrix4.copy(rotateTransform, s.rotation);
                                                else
                                                    LA.Matrix4.fromIdentity(rotateTransform);
                                                LA.Matrix4.mul3(transform, translateTransform, rotateTransform, scaleTransform);
                                                for (i = 0, _b = vs.length; i < _b; i += 3) {
                                                    v[0] = vs[i], v[1] = vs[i + 1], v[2] = vs[i + 2];
                                                    LA.Vector3.transformMat4(v, v, transform);
                                                    vertices[vOffset++] = v[0];
                                                    vertices[vOffset++] = v[1];
                                                    vertices[vOffset++] = v[2];
                                                }
                                                LA.Matrix4.mul(transform, rotateTransform, scaleTransform);
                                                ns = surface.normals;
                                                for (i = 0, _b = ns.length; i < _b; i += 3) {
                                                    v[0] = ns[i], v[1] = ns[i + 1], v[2] = ns[i + 2];
                                                    LA.Vector3.transformMat4(v, v, transform);
                                                    LA.Vector3.normalize(v, v);
                                                    normals[nOffset++] = v[0];
                                                    normals[nOffset++] = v[1];
                                                    normals[nOffset++] = v[2];
                                                }
                                            }
                                            else {
                                                for (i = 0, _b = vs.length; i < _b; i++) {
                                                    vertices[vOffset++] = vs[i];
                                                }
                                                ns = surface.normals;
                                                for (i = 0, _b = ns.length; i < _b; i++) {
                                                    normals[nOffset++] = ns[i];
                                                }
                                            }
                                            break;
                                        }
                                    }
                                    ts = surface.triangleIndices;
                                    for (i = 0, _b = ts.length; i < _b; i++) {
                                        triangles[tOffset++] = startVOffset + ts[i];
                                    }
                                    for (i = 0, _b = surface.vertexCount; i < _b; i++) {
                                        annotation[aOffset++] = s.id;
                                    }
                                }
                                ret = {
                                    vertices: vertices,
                                    vertexCount: size.vertexCount,
                                    triangleIndices: triangles,
                                    triangleCount: size.triangleCount,
                                    normals: normals,
                                    annotation: annotation
                                };
                                return [2 /*return*/, ret];
                        }
                    });
                }); });
            }
            var Builder = /** @class */ (function () {
                function Builder() {
                    this.shapes = [];
                }
                Builder.prototype.add = function (shape) {
                    this.shapes.push(shape);
                    return this;
                };
                Builder.prototype.buildSurface = function () {
                    var normalize = false;
                    for (var _i = 0, _a = this.shapes; _i < _a.length; _i++) {
                        var s = _a[_i];
                        if (s.type === 'DashedLine' || s.type === 'Arrow') {
                            normalize = true;
                            break;
                        }
                    }
                    if (normalize) {
                        var normalized = [];
                        for (var _c = 0, _d = this.shapes; _c < _d.length; _c++) {
                            var s = _d[_c];
                            if (s.type === 'DashedLine') {
                                for (var _e = 0, _f = Primitive.createDashes(s); _e < _f.length; _e++) {
                                    var d = _f[_e];
                                    normalized[normalized.length] = d;
                                }
                            }
                            else if (s.type === 'Arrow') {
                                for (var _g = 0, _h = Primitive.createArrow(s); _g < _h.length; _g++) {
                                    var a = _h[_g];
                                    normalized[normalized.length] = a;
                                }
                            }
                            else {
                                normalized[normalized.length] = s;
                            }
                        }
                        return buildSurface(normalized);
                    }
                    return buildSurface(this.shapes);
                };
                Builder.create = function () {
                    return new Builder();
                };
                return Builder;
            }());
            Primitive.Builder = Builder;
        })(Primitive = Visualization.Primitive || (Visualization.Primitive = {}));
    })(Visualization = LiteMol.Visualization || (LiteMol.Visualization = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        Bootstrap.VERSION = { number: "1.4.4", date: "May 31 2018" };
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        Bootstrap.Immutable = __LiteMolImmutable;
        Bootstrap.Rx = LiteMol.Core.Rx;
        Bootstrap.Zlib = LiteMolZlib;
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            var LRUCache;
            (function (LRUCache) {
                function entry(key, data) {
                    return {
                        previous: null,
                        next: null,
                        inList: false,
                        key: key,
                        data: data
                    };
                }
                LRUCache.entry = entry;
                function create(capacity) {
                    return {
                        entries: new Utils.LinkedList(),
                        capacity: Math.max(1, capacity)
                    };
                }
                LRUCache.create = create;
                function get(cache, key) {
                    for (var e = cache.entries.first; e; e = e.next) {
                        if (e.key === key) {
                            cache.entries.remove(e);
                            cache.entries.addLast(e);
                            return e.data;
                        }
                    }
                    return void 0;
                }
                LRUCache.get = get;
                function set(cache, key, data) {
                    if (cache.entries.count >= cache.capacity) {
                        cache.entries.remove(cache.entries.first);
                    }
                    cache.entries.addLast(entry(key, data));
                    return data;
                }
                LRUCache.set = set;
            })(LRUCache = Utils.LRUCache || (Utils.LRUCache = {}));
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            var DataCompressionMethod;
            (function (DataCompressionMethod) {
                DataCompressionMethod[DataCompressionMethod["None"] = 0] = "None";
                DataCompressionMethod[DataCompressionMethod["Gzip"] = 1] = "Gzip";
            })(DataCompressionMethod = Utils.DataCompressionMethod || (Utils.DataCompressionMethod = {}));
            function readStringFromFile(file) {
                return readFromFileInternal(file, false);
            }
            Utils.readStringFromFile = readStringFromFile;
            function readArrayBufferFromFile(file) {
                return readFromFileInternal(file, true);
            }
            Utils.readArrayBufferFromFile = readArrayBufferFromFile;
            function readFromFile(file, type) {
                return readFromFileInternal(file, type === 'Binary');
            }
            Utils.readFromFile = readFromFile;
            function ajaxGetString(url, title) {
                return ajaxGetInternal(title, url, false, false);
            }
            Utils.ajaxGetString = ajaxGetString;
            function ajaxGetArrayBuffer(url, title) {
                return ajaxGetInternal(title, url, true, false);
            }
            Utils.ajaxGetArrayBuffer = ajaxGetArrayBuffer;
            function ajaxGet(params) {
                return ajaxGetInternal(params.title, params.url, params.type === 'Binary', params.compression === DataCompressionMethod.Gzip);
            }
            Utils.ajaxGet = ajaxGet;
            function decompress(buffer) {
                var gzip = new LiteMolZlib.Gunzip(new Uint8Array(buffer));
                return gzip.decompress();
            }
            function processFile(ctx, asArrayBuffer, compressed, e) {
                return __awaiter(this, void 0, void 0, function () {
                    var data, decompressed;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                data = e.target.result;
                                if (!compressed) return [3 /*break*/, 2];
                                return [4 /*yield*/, ctx.updateProgress('Decompressing...')];
                            case 1:
                                _a.sent();
                                decompressed = decompress(data);
                                if (asArrayBuffer) {
                                    return [2 /*return*/, decompressed.buffer];
                                }
                                else {
                                    return [2 /*return*/, LiteMol.Core.Formats.CIF.Binary.MessagePack.utf8Read(decompressed, 0, decompressed.length)];
                                }
                                return [3 /*break*/, 3];
                            case 2: return [2 /*return*/, data];
                            case 3: return [2 /*return*/];
                        }
                    });
                });
            }
            function readData(ctx, action, data, asArrayBuffer) {
                return new LiteMol.Promise(function (resolve, reject) {
                    data.onerror = function (e) {
                        var error = e.target.error;
                        reject(error ? error : 'Failed.');
                    };
                    data.onabort = function () { return reject(LiteMol.Core.Computation.Aborted); };
                    data.onprogress = function (e) {
                        if (e.lengthComputable) {
                            ctx.updateProgress(action, true, e.loaded, e.total);
                        }
                        else {
                            ctx.updateProgress(action + " " + (e.loaded / 1024 / 1024).toFixed(2) + " MB", true);
                        }
                    };
                    data.onload = function (e) { return resolve(e); };
                });
            }
            function readFromFileInternal(file, asArrayBuffer) {
                var _this = this;
                return Bootstrap.Task.fromComputation('Open File', 'Background', LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                    var reader, isCompressed, e, result;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                reader = new FileReader();
                                isCompressed = /\.gz$/i.test(file.name);
                                if (isCompressed || asArrayBuffer)
                                    reader.readAsArrayBuffer(file);
                                else
                                    reader.readAsBinaryString(file);
                                ctx.updateProgress('Opening file...', function () { return reader.abort(); });
                                return [4 /*yield*/, readData(ctx, 'Reading...', reader, asArrayBuffer)];
                            case 1:
                                e = _a.sent();
                                result = processFile(ctx, asArrayBuffer, isCompressed, e);
                                return [2 /*return*/, result];
                        }
                    });
                }); }));
            }
            var RequestPool = /** @class */ (function () {
                function RequestPool() {
                }
                RequestPool.get = function () {
                    if (this.pool.length) {
                        return this.pool.pop();
                    }
                    return new XMLHttpRequest();
                };
                RequestPool.emptyFunc = function () { };
                RequestPool.deposit = function (req) {
                    if (this.pool.length < this.poolSize) {
                        req.onabort = RequestPool.emptyFunc;
                        req.onerror = RequestPool.emptyFunc;
                        req.onload = RequestPool.emptyFunc;
                        req.onprogress = RequestPool.emptyFunc;
                        this.pool.push(req);
                    }
                };
                RequestPool.pool = [];
                RequestPool.poolSize = 15;
                return RequestPool;
            }());
            function processAjax(ctx, asArrayBuffer, decompressGzip, e) {
                return __awaiter(this, void 0, void 0, function () {
                    var req, buff, gzip, data, text, status_1;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                req = e.target;
                                if (!(req.status >= 200 && req.status < 400)) return [3 /*break*/, 6];
                                if (!asArrayBuffer) return [3 /*break*/, 4];
                                buff = e.target.response;
                                RequestPool.deposit(e.target);
                                if (!decompressGzip) return [3 /*break*/, 2];
                                return [4 /*yield*/, ctx.updateProgress('Decompressing...')];
                            case 1:
                                _a.sent();
                                gzip = new LiteMolZlib.Gunzip(new Uint8Array(buff));
                                data = gzip.decompress();
                                return [2 /*return*/, data.buffer];
                            case 2: return [2 /*return*/, buff];
                            case 3: return [3 /*break*/, 5];
                            case 4:
                                text = e.target.responseText;
                                RequestPool.deposit(e.target);
                                return [2 /*return*/, text];
                            case 5: return [3 /*break*/, 7];
                            case 6:
                                status_1 = req.statusText;
                                RequestPool.deposit(e.target);
                                throw status_1;
                            case 7: return [2 /*return*/];
                        }
                    });
                });
            }
            function ajaxGetInternal(title, url, asArrayBuffer, decompressGzip) {
                var _this = this;
                return Bootstrap.Task.fromComputation(title ? title : 'Download', 'Background', LiteMol.Core.computation(function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                    var xhttp, e, result;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                if (!asArrayBuffer && decompressGzip) {
                                    throw 'Decompress is only available when downloading binary data.';
                                }
                                xhttp = RequestPool.get();
                                xhttp.open('get', url, true);
                                xhttp.responseType = asArrayBuffer ? "arraybuffer" : "text";
                                xhttp.send();
                                ctx.updateProgress('Waiting for server...', function () { return xhttp.abort(); });
                                return [4 /*yield*/, readData(ctx, 'Downloading...', xhttp, asArrayBuffer)];
                            case 1:
                                e = _a.sent();
                                return [4 /*yield*/, processAjax(ctx, asArrayBuffer, decompressGzip, e)];
                            case 2:
                                result = _a.sent();
                                return [2 /*return*/, result];
                        }
                    });
                }); }));
            }
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            var Query;
            (function (Query) {
                "use strict";
                var residueIdRegex = /^\s*([1-9][0-9]*)\s+([_.;:""&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]+)(?:\s+i[:]([.]|[a-zA-Z0-9]))?(?:\s+e[:]([.]|[a-zA-Z0-9]+))?/;
                function normalizeId(id) {
                    if (!id || id === '.' || id === '?')
                        return null;
                    return id;
                }
                function getAuthResidueIdParams(id) {
                    var match = id.match(residueIdRegex);
                    if (!match)
                        return void 0;
                    var authSeqNumber = +match[1] | 0;
                    var authAsymId = normalizeId(match[2]);
                    var insCode = normalizeId(match[3]);
                    var entityId = normalizeId(match[4]);
                    return { entityId: entityId, authSeqNumber: authSeqNumber, authAsymId: authAsymId, insCode: insCode };
                }
                function parseAuthResidueId(ids, separator) {
                    if (separator === void 0) { separator = ','; }
                    var _a;
                    var parts = ids.split(separator).map(function (p) { return getAuthResidueIdParams(p); }).filter(function (p) { return !!p; });
                    return LiteMol.Core.Structure.Query.Builder.toQuery((_a = LiteMol.Core.Structure.Query).residues.apply(_a, parts));
                }
                Query.parseAuthResidueId = parseAuthResidueId;
            })(Query = Utils.Query || (Utils.Query = {}));
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            var Query;
            (function (Query) {
                "use strict";
                var ValueOrError = /** @class */ (function () {
                    function ValueOrError(isError, value, error) {
                        this.isError = isError;
                        this.value = value;
                        this.error = error;
                    }
                    ValueOrError.prototype.bind = function (f) {
                        if (this.isError)
                            return this;
                        return f(this.value);
                    };
                    return ValueOrError;
                }());
                Query.ValueOrError = ValueOrError;
                (function (ValueOrError) {
                    function error(err) {
                        return new ValueOrError(true, void 0, err);
                    }
                    ValueOrError.error = error;
                    function value(v) {
                        return new ValueOrError(true, v);
                    }
                    ValueOrError.value = value;
                })(ValueOrError = Query.ValueOrError || (Query.ValueOrError = {}));
            })(Query = Utils.Query || (Utils.Query = {}));
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            var LinkedList = /** @class */ (function () {
                function LinkedList() {
                    this.count = 0;
                    this.first = null;
                    this.last = null;
                }
                LinkedList.prototype.addFirst = function (item) {
                    item.inList = true;
                    if (this.first)
                        this.first.previous = item;
                    item.next = this.first;
                    this.first = item;
                    this.count++;
                };
                LinkedList.prototype.addLast = function (item) {
                    if (this.last != null) {
                        this.last.next = item;
                    }
                    item.previous = this.last;
                    this.last = item;
                    if (this.first == null) {
                        this.first = item;
                    }
                    item.inList = true;
                    this.count++;
                };
                LinkedList.prototype.remove = function (item) {
                    if (!item.inList)
                        return;
                    item.inList = false;
                    if (item.previous !== null) {
                        item.previous.next = item.next;
                    }
                    else if ( /*first == item*/item.previous === null) {
                        this.first = item.next;
                    }
                    if (item.next !== null) {
                        item.next.previous = item.previous;
                    }
                    else if ( /*last == item*/item.next === null) {
                        this.last = item.previous;
                    }
                    item.next = null;
                    item.previous = null;
                    this.count--;
                };
                return LinkedList;
            }());
            Utils.LinkedList = LinkedList;
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            function padTime(n) { return (n < 10 ? '0' : '') + n; }
            function formatTime(d) {
                var h = d.getHours(), m = d.getMinutes(), s = d.getSeconds();
                return h + ":" + padTime(m) + ":" + padTime(s);
            }
            Utils.formatTime = formatTime;
            function round(n, d) {
                var f = Math.pow(10, d);
                return Math.round(f * n) / f;
            }
            Utils.round = round;
            function formatProgress(p) {
                if (p.isIndeterminate)
                    return p.message;
                var x = (100 * p.current / p.max).toFixed(2);
                return p.message + " " + x + "%";
            }
            Utils.formatProgress = formatProgress;
            function generateUUID() {
                var d = new Date().getTime();
                if (window.performance && typeof window.performance.now === "function") {
                    d += performance.now();
                    ; //use high-precision timer if available
                }
                var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                    var r = (d + Math.random() * 16) % 16 | 0;
                    d = Math.floor(d / 16);
                    return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
                });
                return uuid;
            }
            Utils.generateUUID = generateUUID;
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            var VDWRadii = void 0;
            function vdwRadiusFromElementSymbol(model) {
                if (!VDWRadii)
                    VDWRadii = createVdwRadii();
                return function (names, radii) {
                    return function (i) {
                        var r = radii.get(names[i]);
                        if (r !== void 0)
                            return r;
                        return 1.0;
                    };
                }(model.data.atoms.elementSymbol, VDWRadii);
            }
            Utils.vdwRadiusFromElementSymbol = vdwRadiusFromElementSymbol;
            function createVdwRadii() {
                var vdwRadii = {
                    "H": 1.1,
                    "He": 1.4,
                    "Li": 1.81,
                    "Be": 1.53,
                    "B": 1.92,
                    "C": 1.7,
                    "N": 1.55,
                    "O": 1.52,
                    "F": 1.47,
                    "Ne": 1.54,
                    "Na": 2.27,
                    "Mg": 1.73,
                    "Al": 1.84,
                    "Si": 2.1,
                    "P": 1.8,
                    "S": 1.8,
                    "Cl": 1.75,
                    "Ar": 1.88,
                    "K": 2.75,
                    "Ca": 2.31,
                    "Sc": 2.16,
                    "Ti": 1.87,
                    "V": 1.79,
                    "Cr": 1.89,
                    "Mn": 1.97,
                    "Fe": 1.94,
                    "Co": 1.92,
                    "Ni": 1.84,
                    "Cu": 1.86,
                    "Zn": 2.1,
                    "Ga": 1.87,
                    "Ge": 2.11,
                    "As": 1.85,
                    "Se": 1.9,
                    "Br": 1.83,
                    "Kr": 2.02,
                    "Rb": 3.03,
                    "Sr": 2.49,
                    "Y": 2.19,
                    "Zr": 1.86,
                    "Nb": 2.07,
                    "Mo": 2.09,
                    "Tc": 2.09,
                    "Ru": 2.07,
                    "Rh": 1.95,
                    "Pd": 2.02,
                    "Ag": 2.03,
                    "Cd": 2.3,
                    "In": 1.93,
                    "Sn": 2.17,
                    "Sb": 2.06,
                    "Te": 2.06,
                    "I": 1.98,
                    "Xe": 2.16,
                    "Cs": 3.43,
                    "Ba": 2.68,
                    "La": 2.4,
                    "Ce": 2.35,
                    "Pr": 2.39,
                    "Nd": 2.29,
                    "Pm": 2.36,
                    "Sm": 2.29,
                    "Eu": 2.33,
                    "Gd": 2.37,
                    "Tb": 2.21,
                    "Dy": 2.29,
                    "Ho": 2.16,
                    "Er": 2.35,
                    "Tm": 2.27,
                    "Yb": 2.42,
                    "Lu": 2.21,
                    "Hf": 2.12,
                    "Ta": 2.17,
                    "W": 2.1,
                    "Re": 2.17,
                    "Os": 2.16,
                    "Ir": 2.02,
                    "Pt": 2.09,
                    "Au": 2.17,
                    "Hg": 2.09,
                    "Tl": 1.96,
                    "Pb": 2.02,
                    "Bi": 2.07,
                    "Po": 1.97,
                    "At": 2.02,
                    "Rn": 2.2,
                    "Fr": 3.48,
                    "Ra": 2.83,
                    "Ac": 2.6,
                    "Th": 2.37,
                    "Pa": 2.43,
                    "U": 2.4,
                    "Np": 2.21,
                    "Pu": 2.43,
                    "Am": 2.44,
                    "Cm": 2.45,
                    "Bk": 2.44,
                    "Cf": 2.45,
                    "Es": 2.45,
                    "Fm": 2.45,
                    "Md": 2.46,
                    "No": 2.46,
                    "Lr": 2.46,
                };
                var ret = LiteMol.Core.Utils.FastMap.create();
                for (var e in vdwRadii) {
                    ret.set(e, vdwRadii[e]);
                    ret.set(e.toUpperCase(), vdwRadii[e]);
                    ret.set(e.toLowerCase(), vdwRadii[e]);
                }
                return ret;
            }
            ;
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            "use strict";
            var hasOwnProperty = Object.prototype.hasOwnProperty;
            function shallowClone(o) {
                return LiteMol.Core.Utils.extend({}, o);
            }
            Utils.shallowClone = shallowClone;
            // // uses keys' keys to obtain values from source and return a new object
            // export function pickValues<S, T>(keys: S, source: T): S {
            //     let ret = <any>{};
            //     for (let k of Object.keys(keys)) {
            //         if (hasOwnProperty.call(keys, k)) ret[k] = (source as any)[k];
            //     }
            //     return ret;
            // };
            function shallowEqual(a, b) {
                if (!a) {
                    if (!b)
                        return true;
                    return false;
                }
                if (!b)
                    return false;
                var keys = Object.keys(a);
                if (Object.keys(b).length !== keys.length)
                    return false;
                for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
                    var k = keys_1[_i];
                    if (!hasOwnProperty.call(a, k) || a[k] !== b[k])
                        return false;
                }
                return true;
            }
            Utils.shallowEqual = shallowEqual;
            function deepEqual(a, b) {
                if (!a) {
                    if (!b)
                        return true;
                    return false;
                }
                if (!b)
                    return false;
                var keys = Object.keys(a);
                if (Object.keys(b).length !== keys.length)
                    return false;
                for (var _i = 0, keys_2 = keys; _i < keys_2.length; _i++) {
                    var k = keys_2[_i];
                    if (!hasOwnProperty.call(a, k))
                        return false;
                    var u = a[k];
                    var v = b[k];
                    if (typeof u === 'object' && typeof v === 'object') {
                        if (!deepEqual(u, v))
                            return false;
                    }
                    else if (u !== v)
                        return false;
                }
                return true;
            }
            Utils.deepEqual = deepEqual;
            function _assign(target) {
                for (var s = 1; s < arguments.length; s++) {
                    var from = arguments[s];
                    for (var _i = 0, _a = Object.keys(from); _i < _a.length; _i++) {
                        var key = _a[_i];
                        if (hasOwnProperty.call(from, key)) {
                            target[key] = from[key];
                        }
                    }
                }
                return target;
            }
            Utils.assign = Object.assign || _assign;
            function _shallowMerge1(source, update) {
                var changed = false;
                for (var _i = 0, _a = Object.keys(update); _i < _a.length; _i++) {
                    var k = _a[_i];
                    if (!hasOwnProperty.call(update, k))
                        continue;
                    if (update[k] !== source[k]) {
                        changed = true;
                        break;
                    }
                }
                if (!changed)
                    return source;
                return Utils.assign(shallowClone(source), update);
            }
            function _shallowMerge(source) {
                var ret = source;
                for (var s = 1; s < arguments.length; s++) {
                    if (!arguments[s])
                        continue;
                    ret = _shallowMerge1(source, arguments[s]);
                    if (ret !== source) {
                        for (var i = s + 1; i < arguments.length; i++) {
                            ret = Utils.assign(ret, arguments[i]);
                        }
                        break;
                    }
                }
                return ret;
            }
            Utils.merge = _shallowMerge;
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Service;
        (function (Service) {
            "use strict";
            var Dispatcher = /** @class */ (function () {
                function Dispatcher() {
                    this.LOG_DISPATCH_STREAM = false;
                    this.lanes = [];
                    for (var i = 0; i <= Dispatcher.Lane.Task; i++) {
                        this.lanes.push(new Bootstrap.Rx.Subject());
                    }
                }
                Dispatcher.prototype.dispatch = function (event) {
                    if (this.LOG_DISPATCH_STREAM)
                        console.log(event.type.name, Dispatcher.Lane[event.type.lane], event.data);
                    this.lanes[event.type.lane].onNext(event);
                };
                Dispatcher.prototype.schedule = function (action, onError, timeout) {
                    if (timeout === void 0) { timeout = 1000 / 31; }
                    return setTimeout(function () {
                        if (onError) {
                            try {
                                action.call(null);
                            }
                            catch (e) {
                                onError.call(null, '' + e);
                            }
                        }
                        else {
                            action.call(null);
                        }
                    }, timeout);
                };
                Dispatcher.prototype.getStream = function (type) {
                    return this.lanes[type.lane].filter(function (e) { return e.type === type; });
                };
                Dispatcher.prototype.finished = function () {
                    this.lanes.forEach(function (l) { return l.onCompleted(); });
                };
                return Dispatcher;
            }());
            Service.Dispatcher = Dispatcher;
            (function (Dispatcher) {
                var Lane;
                (function (Lane) {
                    Lane[Lane["Slow"] = 0] = "Slow";
                    Lane[Lane["Fast"] = 1] = "Fast";
                    Lane[Lane["Log"] = 2] = "Log";
                    Lane[Lane["Busy"] = 3] = "Busy";
                    Lane[Lane["Transformer"] = 4] = "Transformer";
                    Lane[Lane["Task"] = 5] = "Task";
                })(Lane = Dispatcher.Lane || (Dispatcher.Lane = {}));
            })(Dispatcher = Service.Dispatcher || (Service.Dispatcher = {}));
        })(Service = Bootstrap.Service || (Bootstrap.Service = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Service;
        (function (Service) {
            "use strict";
            var Logger = /** @class */ (function () {
                function Logger(context) {
                    this.context = context;
                }
                Logger.prototype.log = function (e) {
                    Bootstrap.Event.Log.dispatch(this.context, e);
                };
                Logger.prototype.message = function (m) {
                    this.log({ type: Logger.EntryType.Message, timestamp: new Date(), message: m });
                };
                Logger.prototype.error = function (m) {
                    this.log({ type: Logger.EntryType.Error, timestamp: new Date(), message: m });
                };
                Logger.prototype.warning = function (m) {
                    this.log({ type: Logger.EntryType.Warning, timestamp: new Date(), message: m });
                };
                Logger.prototype.info = function (m) {
                    this.log({ type: Logger.EntryType.Info, timestamp: new Date(), message: m });
                };
                return Logger;
            }());
            Service.Logger = Logger;
            (function (Logger) {
                var EntryType;
                (function (EntryType) {
                    EntryType[EntryType["Message"] = 0] = "Message";
                    EntryType[EntryType["Error"] = 1] = "Error";
                    EntryType[EntryType["Warning"] = 2] = "Warning";
                    EntryType[EntryType["Info"] = 3] = "Info";
                })(EntryType = Logger.EntryType || (Logger.EntryType = {}));
            })(Logger = Service.Logger || (Service.Logger = {}));
        })(Service = Bootstrap.Service || (Bootstrap.Service = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Service;
        (function (Service) {
            "use strict";
        })(Service = Bootstrap.Service || (Bootstrap.Service = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var Computation = LiteMol.Core.Computation;
        var Task = /** @class */ (function () {
            function Task(name, type, computation) {
                this.name = name;
                this.type = type;
                this.computation = computation;
                this.info = {
                    id: serialTaskId++,
                    name: name,
                    type: type,
                    reportTime: false
                };
            }
            Object.defineProperty(Task.prototype, "id", {
                get: function () { return this.info.id; },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(Task.prototype, "reportTime", {
                get: function () { return this.info.reportTime; },
                enumerable: true,
                configurable: true
            });
            Task.prototype.run = function (context) {
                return this.runWithContext(context).result;
            };
            Task.prototype.runWithContext = function (context) {
                return new Task.Running(context, this.computation, this.info);
            };
            Task.prototype.setReportTime = function (report) {
                this.info.reportTime = report;
                return this;
            };
            return Task;
        }());
        Bootstrap.Task = Task;
        var serialTaskId = 0;
        (function (Task) {
            Task.__DEBUG_MODE__ = false;
            var Running = /** @class */ (function () {
                function Running(context, computation, info) {
                    this.context = context;
                    this.computation = computation;
                    this.info = info;
                    this.run();
                }
                Running.prototype.tryAbort = function () {
                    this.computationCtx.requestAbort();
                };
                Running.prototype.progressUpdated = function (progress) {
                    Bootstrap.Event.Task.StateUpdated.dispatch(this.context, {
                        taskId: this.info.id,
                        type: this.info.type,
                        name: this.info.name,
                        message: Bootstrap.Utils.formatProgress(progress),
                        abort: progress.requestAbort
                    });
                };
                Running.prototype.resolved = function () {
                    try {
                        this.context.performance.end('task' + this.info.id);
                        if (this.info.reportTime) {
                            var time = this.context.performance.time('task' + this.info.id);
                            if (this.info.type !== 'Silent')
                                this.context.logger.info(this.info.name + " finished in " + LiteMol.Core.Utils.PerformanceMonitor.format(time) + ".");
                        }
                    }
                    finally {
                        Bootstrap.Event.Task.Completed.dispatch(this.context, this.info.id);
                    }
                };
                Running.prototype.rejected = function (err) {
                    this.context.performance.end('task' + this.info.id);
                    this.context.performance.formatTime('task' + this.info.id);
                    if (Task.__DEBUG_MODE__) {
                        console.error(err);
                    }
                    try {
                        if (this.info.type === 'Silent') {
                            if (err.warn)
                                this.context.logger.warning("Warning (" + this.info.name + "): " + err.message);
                            else
                                console.error("Error (" + this.info.name + ")", err);
                        }
                        else {
                            if (err.warn) {
                                this.context.logger.warning("Warning (" + this.info.name + "): " + err.message);
                            }
                            else {
                                var e = '' + err;
                                if (e.indexOf('Aborted') >= 0)
                                    this.context.logger.info(this.info.name + ": Aborted.");
                                else
                                    this.context.logger.error("Error (" + this.info.name + "): " + err);
                            }
                        }
                    }
                    catch (e) {
                        console.error(e);
                    }
                    finally {
                        Bootstrap.Event.Task.Completed.dispatch(this.context, this.info.id);
                    }
                };
                Running.prototype.run = function () {
                    var _this = this;
                    this.computationCtx = Computation.createContext();
                    this.computationCtx.progress.subscribe(function (p) { return _this.progressUpdated(p); });
                    Bootstrap.Event.Task.Started.dispatch(this.context, this.info);
                    this.context.performance.start('task' + this.info.id);
                    this.result = this.computation.run(this.computationCtx);
                    this.result.then(function () { return _this.resolved(); }).catch(function (e) { return _this.rejected(e); });
                };
                return Running;
            }());
            Task.Running = Running;
            function create(name, type, computation) {
                return new Task(name, type, LiteMol.Core.computation(computation));
            }
            Task.create = create;
            function resolve(name, type, value) {
                return new Task(name, type, Computation.resolve(value));
            }
            Task.resolve = resolve;
            function reject(name, type, reason) {
                return new Task(name, type, Computation.reject(reason));
            }
            Task.reject = reject;
            function fromComputation(name, type, computation) {
                return new Task(name, type, computation);
            }
            Task.fromComputation = fromComputation;
            function isPromise(t) {
                return t.then && t.catch;
            }
            Task.isPromise = isPromise;
        })(Task = Bootstrap.Task || (Bootstrap.Task = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var Event;
        (function (Event) {
            var EventPrototype = {
                dispatch: function (context, data) { context.dispatcher.dispatch({ type: this, data: data }); },
                getStream: function (context) { return context.dispatcher.getStream(this); }
            };
            function create(name, lane) {
                return Object.create(EventPrototype, {
                    name: { writable: false, configurable: false, value: name },
                    lane: { writable: false, configurable: false, value: lane }
                });
            }
            Event.create = create;
        })(Event = Bootstrap.Event || (Bootstrap.Event = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Event;
        (function (Event) {
            "use strict";
            var Lane = Bootstrap.Service.Dispatcher.Lane;
            Event.Log = Event.create('bs.Log', Lane.Log);
            var Common;
            (function (Common) {
                Common.LayoutChanged = Event.create('bs.Common.LayoutChanged', Lane.Slow);
                Common.ComponentsChanged = Event.create('bs.Common.ComponentsChanged', Lane.Slow);
            })(Common = Event.Common || (Event.Common = {}));
            var Task;
            (function (Task) {
                Task.Started = Event.create('bs.Tasks.Started', Lane.Task);
                Task.Completed = Event.create('bs.Tasks.Completed', Lane.Task);
                Task.StateUpdated = Event.create('bs.Tasks.StateUpdated', Lane.Busy);
            })(Task = Event.Task || (Event.Task = {}));
            var Tree;
            (function (Tree) {
                Tree.NodeUpdated = Event.create('bs.Tree.NodeUpdated', Lane.Slow);
                Tree.NodeAdded = Event.create('bs.Tree.NodeAdded', Lane.Slow);
                Tree.NodeRemoved = Event.create('bs.Tree.NodeRemoved', Lane.Slow);
                Tree.TransformStarted = Event.create('bs.Tree.TransformStarted', Lane.Slow);
                Tree.TransformFinished = Event.create('bs.Tree.TransformFinished', Lane.Slow);
                Tree.TransformerApply = Event.create('bs.Tree.TransformerApplied', Lane.Transformer);
            })(Tree = Event.Tree || (Event.Tree = {}));
            var Entity;
            (function (Entity_1) {
                Entity_1.CurrentChanged = Event.create('bs.Entity.CurrentChanged', Lane.Slow);
            })(Entity = Event.Entity || (Event.Entity = {}));
            var Interactivity;
            (function (Interactivity) {
                Interactivity.Highlight = Event.create('bs.Visuals.HoverElement', Lane.Fast);
            })(Interactivity = Event.Interactivity || (Event.Interactivity = {}));
            var Visual;
            (function (Visual) {
                Visual.VisualHoverElement = Event.create('bs.Visual.HoverElement', Lane.Fast);
                Visual.VisualSelectElement = Event.create('bs.Visual.SelectElement', Lane.Fast);
                Visual.CameraChanged = Event.create('bs.Visual.CameraChanged', Lane.Fast);
            })(Visual = Event.Visual || (Event.Visual = {}));
            var Molecule;
            (function (Molecule) {
                Molecule.ModelHighlight = Event.create('bs.Molecule.ModelHighlight', Lane.Fast);
                Molecule.ModelSelect = Event.create('bs.Molecule.ModelSelect', Lane.Fast);
            })(Molecule = Event.Molecule || (Event.Molecule = {}));
        })(Event = Bootstrap.Event || (Bootstrap.Event = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Command;
        (function (Command) {
            "use strict";
            var Lane = Bootstrap.Service.Dispatcher.Lane;
            var create = Bootstrap.Event.create;
            var Tree;
            (function (Tree) {
                Tree.RemoveNode = create('bs.cmd.Tree.RemoveNode', Lane.Slow);
                Tree.ApplyTransform = create('bs.cmd.Tree.ApplyTransform', Lane.Slow);
            })(Tree = Command.Tree || (Command.Tree = {}));
            var Entity;
            (function (Entity) {
                Entity.SetCurrent = create('bs.cmd.Entity.SetCurrentNode', Lane.Slow);
                Entity.ToggleExpanded = create('bs.cmd.Entity.ToggleExpanded', Lane.Slow);
                Entity.SetVisibility = create('bs.cmd.Entity.SetVisibility', Lane.Slow);
                Entity.Focus = create('bs.cmd.Entity.Focus', Lane.Slow);
                Entity.Highlight = create('bs.cmd.Entity.Highlight', Lane.Slow);
            })(Entity = Command.Entity || (Command.Entity = {}));
            var Layout;
            (function (Layout) {
                Layout.SetState = LiteMol.Bootstrap.Event.create('lm.cmd.Layout.SetState', Lane.Slow);
                Layout.SetViewportOptions = create('bs.cmd.Layout.SetViewportOptions', Lane.Slow);
            })(Layout = Command.Layout || (Command.Layout = {}));
            var Molecule;
            (function (Molecule) {
                Molecule.FocusQuery = create('bs.cmd.Molecule.FocusQuery', Lane.Slow);
                Molecule.Highlight = create('bs.cmd.Molecule.Highlight', Lane.Slow);
                Molecule.CreateSelectInteraction = create('bs.cmd.Molecule.CreateSelectInteraction', Lane.Slow);
            })(Molecule = Command.Molecule || (Command.Molecule = {}));
            var Visual;
            (function (Visual) {
                Visual.ResetScene = create('bs.cmd.Visual.ResetScene', Lane.Slow);
                Visual.ResetTheme = create('bs.cmd.Visual.ResetTheme', Lane.Slow);
                Visual.UpdateBasicTheme = create('bs.cmd.Visual.UpdateBasicTheme', Lane.Slow);
            })(Visual = Command.Visual || (Command.Visual = {}));
            var Toast;
            (function (Toast) {
                Toast.Show = create('bs.cmd.Toast.Show', Lane.Slow);
                Toast.Hide = create('bs.cmd.Toast.Hide', Lane.Slow);
            })(Toast = Command.Toast || (Command.Toast = {}));
        })(Command = Bootstrap.Command || (Bootstrap.Command = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var Tree;
        (function (Tree) {
            function create(context, root) {
                var tree = {
                    version: 0,
                    refs: LiteMol.Core.Utils.FastMap.create(),
                    nodes: LiteMol.Core.Utils.FastSet.create(),
                    root: root,
                    context: context
                };
                root.parent = root;
                root.tree = tree;
                return tree;
            }
            Tree.create = create;
            function _addRef(entity) {
                if (!entity.tree)
                    return;
                var refs = entity.tree.refs.get(entity.ref);
                if (!refs) {
                    entity.tree.refs.set(entity.ref, [entity]);
                }
                else {
                    refs.push(entity);
                }
            }
            function addRef(entity) {
                Tree.Node.forEach(entity, function (e) { return _addRef(e); });
            }
            function _removeRef(tree, entity) {
                var refs = tree.refs.get(entity.ref);
                if (!refs)
                    return;
                var i = refs.indexOf(entity);
                if (i < 0)
                    return;
                refs[i] = refs[refs.length - 1];
                refs.pop();
                if (!refs.length)
                    tree.refs.delete(entity.ref);
            }
            function add(node) {
                if (!node.parent)
                    throw 'Cannot add a node without a parent.';
                var tree = node.parent.tree;
                Tree.Node.forEach(node, function (e) { return e.tree = tree; });
                Tree.Node.addChild(node.parent, node);
                addRef(node);
                Bootstrap.Entity.nodeUpdated(node.parent);
                notifyAdded(node);
            }
            Tree.add = add;
            function notifyAdded(node) {
                var ctx = node.tree.context;
                Tree.Node.forEachPreorder(node, function (n) {
                    Bootstrap.Event.Tree.NodeAdded.dispatch(ctx, n);
                });
            }
            function update(tree, old, e) {
                Tree.Node.replaceChild(old.parent, old, e);
                notifyRemoved(tree.context, old);
                Tree.Node.forEach(e, function (n) { return n.tree = tree; });
                addRef(e);
                for (var _i = 0, _a = e.children; _i < _a.length; _i++) {
                    var c = _a[_i];
                    notifyAdded(c);
                }
                Bootstrap.Entity.nodeUpdated(e.parent);
                Bootstrap.Event.Tree.NodeAdded.dispatch(tree.context, e);
                if (tree.context.currentEntity === old) {
                    Bootstrap.Entity.setCurrent(e);
                }
            }
            Tree.update = update;
            function updatePath(node) {
                if (!node)
                    return;
                var top = void 0;
                while (node !== node.parent) {
                    top = node;
                    Tree.Node.update(node);
                    node = node.parent;
                }
                if (top)
                    Bootstrap.Event.Tree.NodeUpdated.dispatch(node.tree.context, top);
            }
            Tree.updatePath = updatePath;
            function clearRoot(tree) {
                var children = tree.root.children;
                tree.root.children = [];
                Tree.Node.update(tree.root);
                Bootstrap.Entity.nodeUpdated(tree.root);
                tree.refs.clear();
                for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
                    var c = children_1[_i];
                    notifyRemoved(tree.context, c);
                }
                Bootstrap.Command.Entity.SetCurrent.dispatch(tree.context, tree.root);
            }
            function notifyRemoved(ctx, node) {
                var current = ctx.currentEntity;
                var hasCurrent = false;
                Tree.Node.forEach(node, function (n) {
                    _removeRef(ctx.tree, n);
                    Bootstrap.Event.Tree.NodeRemoved.dispatch(ctx, n);
                    n.tree = void 0;
                    if (n === current)
                        hasCurrent = true;
                });
                return hasCurrent;
            }
            function remove(node) {
                if (!node || !node.tree)
                    return;
                if (node.parent === node) { // root
                    clearRoot(node.tree);
                    return;
                }
                var isHidden = Tree.Node.isHidden(node);
                var index = node.index;
                var parent = node.parent;
                var ctx = node.tree.context;
                Tree.Node.removeChild(parent, node);
                Bootstrap.Entity.nodeUpdated(parent);
                var hasCurrent = notifyRemoved(ctx, node);
                if (hasCurrent && !isHidden) {
                    var foundSibling = false;
                    for (var i = index; i >= 0; i--) {
                        if (parent.children[i] && !Tree.Node.isHidden(parent.children[i])) {
                            Bootstrap.Command.Entity.SetCurrent.dispatch(ctx, parent.children[i]);
                            foundSibling = true;
                            break;
                        }
                    }
                    if (!foundSibling) {
                        Bootstrap.Command.Entity.SetCurrent.dispatch(ctx, parent);
                    }
                }
                if (node.transform.props.isBinding && !parent.children.length) {
                    remove(node.parent);
                }
            }
            Tree.remove = remove;
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Tree;
        (function (Tree) {
            "use strict";
            ;
            var Node;
            (function (Node) {
                Node.Null = {};
                function is(e, t) {
                    return e && e.type === t;
                }
                Node.is = is;
                function hasAncestor(e, a) {
                    if (!a)
                        return false;
                    while (true) {
                        if (e === a)
                            return true;
                        e = e.parent;
                        if (!e || e === e.parent)
                            return false;
                    }
                }
                Node.hasAncestor = hasAncestor;
                function findAncestor(e, t) {
                    if (!e)
                        return void 0;
                    var n = e.parent;
                    while (true) {
                        if (is(n, t))
                            return n;
                        n = n.parent;
                        if (n.parent === n)
                            return void 0;
                    }
                }
                Node.findAncestor = findAncestor;
                // search towards the root
                function findClosestNodeOfType(e, t) {
                    if (!e)
                        return void 0;
                    var n = e;
                    while (true) {
                        if (t.indexOf(n.type) >= 0)
                            return n;
                        n = n.parent;
                        if (n.parent === n) {
                            return t.indexOf(n.type) >= 0 ? n : void 0;
                        }
                    }
                }
                Node.findClosestNodeOfType = findClosestNodeOfType;
                var serialId = 0;
                function createId() {
                    return serialId++;
                }
                Node.createId = createId;
                function update(e) {
                    e.version++;
                    return e;
                }
                Node.update = update;
                function withProps(n, props) {
                    var newProps = Bootstrap.Utils.merge(n.props, props);
                    if (newProps === n.props)
                        return n;
                    return update(n);
                }
                Node.withProps = withProps;
                function withState(n, state) {
                    var ns = Bootstrap.Utils.merge(n.state, state);
                    if (ns === n.state)
                        return n;
                    n.state = ns;
                    return update(n);
                }
                Node.withState = withState;
                function addChild(n, c) {
                    c.index = n.children.length;
                    n.children.push(c);
                    return update(n);
                }
                Node.addChild = addChild;
                function removeChild(n, child) {
                    var children = n.children;
                    for (var i = child.index, _b = children.length - 1; i < _b; i++) {
                        var c = children[i + 1];
                        c.index--;
                        children[i] = c;
                    }
                    children.pop();
                    return update(n);
                }
                Node.removeChild = removeChild;
                function replaceChild(n, oldChild, newChild) {
                    if (!newChild)
                        return removeChild(n, oldChild);
                    newChild.index = oldChild.index;
                    n.children[newChild.index] = newChild;
                    return update(n);
                }
                Node.replaceChild = replaceChild;
                function forEach(n, f) {
                    for (var _i = 0, _a = n.children; _i < _a.length; _i++) {
                        var c = _a[_i];
                        forEach(c, f);
                    }
                    f(n);
                }
                Node.forEach = forEach;
                function forEachPreorder(n, f) {
                    f(n);
                    for (var _i = 0, _a = n.children; _i < _a.length; _i++) {
                        var c = _a[_i];
                        forEach(c, f);
                    }
                }
                Node.forEachPreorder = forEachPreorder;
                function collect(n) {
                    var nodes = [];
                    forEach(n, function (c) { return nodes.push(c); });
                    return nodes;
                }
                Node.collect = collect;
                function isHidden(e) {
                    if (e.isHidden)
                        return true;
                    var n = e.parent;
                    if (!n)
                        return e.isHidden;
                    while (n.parent !== n) {
                        if (n.isHidden) {
                            return true;
                        }
                        n = n.parent;
                        if (!n)
                            return false;
                    }
                    return false;
                }
                Node.isHidden = isHidden;
            })(Node = Tree.Node || (Tree.Node = {}));
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Tree;
        (function (Tree) {
            "use strict";
            var Selection;
            (function (Selection) {
                function select(s, tree) {
                    return compile(s)(tree);
                }
                Selection.select = select;
                function compile(s) {
                    var selector = s ? s : Selection.root();
                    var query;
                    if (isBuilder(selector))
                        query = selector.compile();
                    else if (isEntity(selector))
                        query = Selection.byValue(selector).compile();
                    else if (isQuery(selector))
                        query = selector;
                    else
                        query = Selection.byRef(selector).compile();
                    return query;
                }
                Selection.compile = compile;
                function isEntity(arg) {
                    return arg.ref !== void 0;
                }
                function isBuilder(arg) {
                    return arg.compile !== void 0;
                }
                function isQuery(arg) {
                    return typeof arg === 'function';
                }
                var Helpers;
                (function (Helpers) {
                    Helpers.BuilderPrototype = {};
                    function registerModifier(name, f) {
                        Helpers.BuilderPrototype[name] = function () {
                            var args = [];
                            for (var _i = 0; _i < arguments.length; _i++) {
                                args[_i] = arguments[_i];
                            }
                            return f.call.apply(f, [void 0, this].concat(args));
                        };
                    }
                    Helpers.registerModifier = registerModifier;
                })(Helpers = Selection.Helpers || (Selection.Helpers = {}));
                function build(compile) {
                    return Object.create(Helpers.BuilderPrototype, { compile: { writable: false, configurable: false, value: compile } });
                }
                function root() { return build(function () { return function (tree) { return [tree.root]; }; }); }
                Selection.root = root;
                function byRef() {
                    var refs = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        refs[_i] = arguments[_i];
                    }
                    return build(function () { return function (tree) {
                        var ret = [];
                        for (var _i = 0, refs_1 = refs; _i < refs_1.length; _i++) {
                            var ref = refs_1[_i];
                            var xs = tree.refs.get(ref);
                            if (!xs)
                                continue;
                            for (var _a = 0, xs_1 = xs; _a < xs_1.length; _a++) {
                                var x = xs_1[_a];
                                ret.push(x);
                            }
                        }
                        return ret;
                    }; });
                }
                Selection.byRef = byRef;
                function byValue() {
                    var entities = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        entities[_i] = arguments[_i];
                    }
                    return build(function () { return function (tree) { return entities; }; });
                }
                Selection.byValue = byValue;
                Helpers.registerModifier('flatMap', flatMap);
                function flatMap(b, f) {
                    var q = compile(b);
                    return build(function () { return function (tree) {
                        var ret = [];
                        for (var _i = 0, _a = q(tree); _i < _a.length; _i++) {
                            var n = _a[_i];
                            for (var _b = 0, _c = f(n); _b < _c.length; _b++) {
                                var m = _c[_b];
                                ret.push(m);
                            }
                        }
                        return ret;
                    }; });
                }
                Selection.flatMap = flatMap;
                Helpers.registerModifier('mapEntity', mapEntity);
                function mapEntity(b, f) {
                    var q = compile(b);
                    return build(function () { return function (tree) {
                        var ret = [];
                        for (var _i = 0, _a = q(tree); _i < _a.length; _i++) {
                            var n = _a[_i];
                            var x = f(n);
                            if (x)
                                ret.push(x);
                        }
                        return ret;
                    }; });
                }
                Selection.mapEntity = mapEntity;
                Helpers.registerModifier('unique', unique);
                function unique(b) {
                    var q = compile(b);
                    return build(function () { return function (tree) {
                        var set = LiteMol.Core.Utils.FastSet.create();
                        var ret = [];
                        for (var _i = 0, _a = q(tree); _i < _a.length; _i++) {
                            var n = _a[_i];
                            if (!set.has(n.id)) {
                                set.add(n.id);
                                ret.push(n);
                            }
                        }
                        return ret;
                    }; });
                }
                Selection.unique = unique;
                Helpers.registerModifier('first', first);
                function first(b) { var q = compile(b); return build(function () { return function (tree) { return [q(tree)[0]]; }; }); }
                Selection.first = first;
                Helpers.registerModifier('filter', filter);
                function filter(b, p) { return flatMap(b, function (n) { return p(n) ? [n] : []; }); }
                Selection.filter = filter;
                Helpers.registerModifier('subtree', subtree);
                function subtree(b) { return flatMap(b, function (n) { return Tree.Node.collect(n); }); }
                Selection.subtree = subtree;
                Helpers.registerModifier('children', children);
                function children(b) { return flatMap(b, function (n) { return n.children; }); }
                Selection.children = children;
                Helpers.registerModifier('ofType', ofType);
                function ofType(b, t) { return filter(b, function (n) { return n.type === t; }); }
                Selection.ofType = ofType;
                Helpers.registerModifier('ancestorOfType', ancestorOfType);
                function ancestorOfType(b, t) { return unique(mapEntity(b, function (n) { return Tree.Node.findAncestor(n, t); })); }
                Selection.ancestorOfType = ancestorOfType;
                Helpers.registerModifier('parent', parent);
                function parent(b) { return unique(mapEntity(b, function (n) { return n.parent; })); }
                Selection.parent = parent;
            })(Selection = Tree.Selection || (Tree.Selection = {}));
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Tree;
        (function (Tree) {
            "use strict";
            var Transformer;
            (function (Transformer) {
                var TransformerImpl = /** @class */ (function () {
                    function TransformerImpl(info, transform, updater) {
                        this.info = info;
                        this.transform = transform;
                        this.updater = updater;
                    }
                    TransformerImpl.prototype.getTarget = function (node) {
                        var info = this.info;
                        return (!info.from.length ? node : Tree.Node.findClosestNodeOfType(node, info.from));
                    };
                    TransformerImpl.prototype.checkTypes = function (a, t) {
                        if (t.transformer !== this) {
                            return "The transform is calling an invalid transformer (got " + t.transformer.info.name + ", expected " + this.info.name + ")";
                        }
                        var info = this.info;
                        if (info.from.length && info.from.indexOf(a.type) < 0) {
                            return "Transform (" + info.name + "): type error, expected '" + info.from.map(function (t) { return t.info.name; }).join('/') + "', got '" + a.type.info.name + "'.";
                        }
                        return void 0;
                    };
                    TransformerImpl.prototype.validateParams = function (t) {
                        var info = this.info;
                        if (info.validateParams) {
                            var issues = info.validateParams(t.params);
                            if (issues && issues.length > 0) {
                                return "Invalid params: " + issues.join(', ') + ".";
                            }
                        }
                        return void 0;
                    };
                    TransformerImpl.prototype.validate = function (a, t) {
                        var info = this.info;
                        if (!a)
                            return Bootstrap.Task.reject(info.name, 'Normal', 'Could not find a suitable node to apply the transformer to.');
                        var typeCheck = this.checkTypes(a, t);
                        if (typeCheck)
                            return Bootstrap.Task.reject(info.name, 'Normal', typeCheck);
                        var paramValidation = this.validateParams(t);
                        if (paramValidation)
                            return Bootstrap.Task.reject(info.name, 'Normal', paramValidation);
                        return void 0;
                    };
                    TransformerImpl.prototype.apply = function (context, node, t) {
                        if (this.info.isComposed)
                            return this.transform(context, node, t);
                        var a = this.getTarget(node);
                        var validationFailed = this.validate(a, t);
                        if (validationFailed)
                            return validationFailed;
                        Bootstrap.Event.Tree.TransformerApply.dispatch(context, { a: a, t: t });
                        return this.transform(context, a, t);
                    };
                    TransformerImpl.prototype.update = function (context, b, t) {
                        var node = b.parent;
                        if (this.info.isComposed && !this.updater)
                            return this.transform(context, node, t);
                        if (this.updater) {
                            var paramValidation = this.validateParams(t);
                            if (paramValidation)
                                return Bootstrap.Task.reject(this.info.name, 'Normal', paramValidation);
                            var updated = this.updater(context, b, t);
                            if (updated)
                                return updated;
                        }
                        Bootstrap.Event.Tree.TransformerApply.dispatch(context, { a: b.parent, t: t });
                        return this.transform(context, node, t);
                    };
                    TransformerImpl.prototype.create = function (params, props) {
                        return Tree.Transform.create(params, props ? props : {}, this);
                    };
                    return TransformerImpl;
                }());
                function create(info, transform, updater) {
                    return new TransformerImpl(info, transform, updater);
                }
                Transformer.create = create;
                function internal(id, from, to, transform) {
                    return create({
                        id: id,
                        name: id,
                        description: '',
                        from: from,
                        to: to,
                        validateParams: function () { return void 0; },
                        defaultParams: function () { return ({}); }
                    }, transform);
                }
                Transformer.internal = internal;
                function rejectAction(actionContext, error, context, reject, onError) {
                    try {
                        reject(error);
                    }
                    finally {
                        if (onError) {
                            if (typeof onError === 'string') {
                                context.logger.error(onError);
                            }
                            else {
                                setTimeout(function () { return onError.call(null, context, actionContext, error); }, 0);
                            }
                        }
                    }
                }
                function resolveAction(src, context, resolve, reject, onDone, onError) {
                    return __awaiter(this, void 0, void 0, function () {
                        var hadError, e_2;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    hadError = false;
                                    _a.label = 1;
                                case 1:
                                    _a.trys.push([1, 3, , 4]);
                                    return [4 /*yield*/, Tree.Transform.apply(context, src.action).run()];
                                case 2:
                                    _a.sent();
                                    try {
                                        resolve(Tree.Node.Null);
                                    }
                                    finally {
                                        if (onDone) {
                                            if (typeof onDone === 'string') {
                                                if (!hadError)
                                                    context.logger.message(onDone);
                                            }
                                            else {
                                                setTimeout(function () { return onDone.call(null, context, src.context); }, 0);
                                            }
                                        }
                                    }
                                    return [3 /*break*/, 4];
                                case 3:
                                    e_2 = _a.sent();
                                    hadError = true;
                                    try {
                                        reject(e_2);
                                    }
                                    finally {
                                        if (onError) {
                                            if (typeof onError === 'string') {
                                                context.logger.error(onError);
                                            }
                                            else {
                                                setTimeout(function () { return onError.call(null, context, src.context, e_2); }, 0);
                                            }
                                        }
                                    }
                                    return [3 /*break*/, 4];
                                case 4: return [2 /*return*/];
                            }
                        });
                    });
                }
                function action(info, builder, onDone, onError) {
                    return create(info, function (context, a, t) {
                        return Bootstrap.Task.create(info.name, 'Background', function (ctx) { return new LiteMol.Promise(function (res, rej) {
                            try {
                                var src = builder(context, a, t);
                                resolveAction({ action: src, context: void 0 }, context, res, rej, onDone, onError);
                            }
                            catch (e) {
                                rej(e);
                            }
                        }); });
                    });
                }
                Transformer.action = action;
                function actionWithContext(info, builder, onDone, onError) {
                    return create(info, function (context, a, t) {
                        return Bootstrap.Task.create(info.name, 'Background', function (ctx) { return new LiteMol.Promise(function (res, rej) {
                            try {
                                var src = builder(context, a, t);
                                if (Bootstrap.Task.isPromise(src)) {
                                    src
                                        .then(function (s) { return resolveAction(s, context, res, rej, onDone, onError); })
                                        .catch(function (e) { return rejectAction(void 0, e, context, rej, onError); });
                                }
                                else {
                                    resolveAction(src, context, res, rej, onDone, onError);
                                }
                            }
                            catch (e) {
                                rej(e);
                            }
                        }); });
                    });
                }
                Transformer.actionWithContext = actionWithContext;
            })(Transformer = Tree.Transformer || (Tree.Transformer = {}));
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Tree;
        (function (Tree) {
            "use strict";
            var Transform;
            (function (Transform) {
                var TransformImpl = /** @class */ (function () {
                    function TransformImpl(params, props, transformer) {
                        this.params = params;
                        this.props = props;
                        this.transformer = transformer;
                        this.isUpdate = false;
                    }
                    TransformImpl.prototype.resolveAdd = function (a, b) {
                        if (b === Tree.Node.Null) {
                            return b;
                        }
                        b.ref = this.props.ref;
                        if (this.props.isHidden)
                            b.isHidden = true;
                        if (!b.tree) {
                            b.parent = a;
                            Tree.add(b);
                        }
                        return b;
                    };
                    TransformImpl.prototype.resolveUpdate = function (context, b, newB) {
                        if (newB === Tree.Node.Null) {
                            return newB;
                        }
                        var a = b.parent;
                        newB.ref = this.props.ref;
                        newB.parent = a;
                        newB.tag = b.tag;
                        newB.state = b.state;
                        if (this.props.isHidden)
                            newB.isHidden = true;
                        Tree.update(context.tree, b, newB);
                        return newB;
                    };
                    TransformImpl.prototype.apply = function (context, a) {
                        var _this = this;
                        return LiteMol.Core.computation(function (ctx) { return new LiteMol.Promise(function (res, rej) { return __awaiter(_this, void 0, void 0, function () {
                            var _this = this;
                            return __generator(this, function (_a) {
                                Bootstrap.Event.Tree.TransformStarted.dispatch(context, this);
                                this.transformer.apply(context, a, this).run(context).then(function (b) {
                                    res(_this.resolveAdd(a, b));
                                    Bootstrap.Event.Tree.TransformFinished.dispatch(context, { transform: _this });
                                }).catch(function (e) {
                                    rej(e);
                                    Bootstrap.Event.Tree.TransformFinished.dispatch(context, { transform: _this, error: e });
                                });
                                return [2 /*return*/];
                            });
                        }); }); });
                    };
                    TransformImpl.prototype.update = function (context, b) {
                        var _this = this;
                        return LiteMol.Core.computation(function (ctx) { return new LiteMol.Promise(function (res, rej) {
                            _this.isUpdate = true;
                            _this.props.ref = b.transform.props.ref;
                            Bootstrap.Event.Tree.TransformStarted.dispatch(context, _this);
                            if (b.transform.props.isBinding)
                                _this.props.isBinding = true;
                            _this.transformer.update(context, b, _this).run(context)
                                .then(function (newB) {
                                res(_this.resolveUpdate(context, b, newB));
                                Bootstrap.Event.Tree.TransformFinished.dispatch(context, { transform: _this });
                            }).catch(function (e) {
                                rej(e);
                                Bootstrap.Event.Tree.TransformFinished.dispatch(context, { transform: _this, error: e });
                            });
                        }); });
                    };
                    return TransformImpl;
                }());
                function create(params, props, transformer) {
                    var p = Bootstrap.Utils.shallowClone(props);
                    if (!p.ref)
                        p.ref = Bootstrap.Utils.generateUUID();
                    return new TransformImpl(params, p, transformer);
                }
                Transform.create = create;
                function isInstance(arg) {
                    return !!arg.selector;
                }
                function isBuilder(arg) {
                    return !!arg.compile;
                }
                function execute(ctx, source, isUpdate) {
                    var _this = this;
                    var instances;
                    try {
                        if (isInstance(source))
                            instances = [source];
                        else if (isBuilder(source))
                            instances = source.compile();
                        else
                            instances = source;
                    }
                    catch (e) {
                        return LiteMol.Core.Computation.reject(e);
                    }
                    return LiteMol.Core.computation(function () { return __awaiter(_this, void 0, void 0, function () {
                        var _i, instances_1, i, xs, _a, xs_2, x, e_3;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0:
                                    _i = 0, instances_1 = instances;
                                    _b.label = 1;
                                case 1:
                                    if (!(_i < instances_1.length)) return [3 /*break*/, 8];
                                    i = instances_1[_i];
                                    xs = ctx.select(i.selector);
                                    _a = 0, xs_2 = xs;
                                    _b.label = 2;
                                case 2:
                                    if (!(_a < xs_2.length)) return [3 /*break*/, 7];
                                    x = xs_2[_a];
                                    _b.label = 3;
                                case 3:
                                    _b.trys.push([3, 5, , 6]);
                                    return [4 /*yield*/, (isUpdate ? i.transform.update(ctx, x) : i.transform.apply(ctx, x)).run()];
                                case 4:
                                    _b.sent();
                                    return [3 /*break*/, 6];
                                case 5:
                                    e_3 = _b.sent();
                                    return [3 /*break*/, 6];
                                case 6:
                                    _a++;
                                    return [3 /*break*/, 2];
                                case 7:
                                    _i++;
                                    return [3 /*break*/, 1];
                                case 8: return [2 /*return*/];
                            }
                        });
                    }); });
                }
                Transform.execute = execute;
                function apply(ctx, source) {
                    return execute(ctx, source, false);
                }
                Transform.apply = apply;
                function update(ctx, source) {
                    return execute(ctx, source, true);
                }
                Transform.update = update;
            })(Transform = Tree.Transform || (Tree.Transform = {}));
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Tree;
        (function (Tree) {
            var Transform;
            (function (Transform) {
                "use strict";
                function build() {
                    return new Builder.Impl(void 0, []);
                }
                Transform.build = build;
                var Builder;
                (function (Builder) {
                    var Impl = /** @class */ (function () {
                        function Impl(last, transforms) {
                            this.last = last;
                            this.transforms = transforms;
                        }
                        Impl.prototype.add = function (s, t, params, props) {
                            var i = { selector: s, transform: t.create(params, props) };
                            this.transforms.push(i);
                            this.last = i;
                            return new Impl(i, this.transforms);
                        };
                        Impl.prototype.then = function (t, params, props) {
                            if (!this.last)
                                throw "Cannot 'then' on an empty builder";
                            var transform = t.create(params, props);
                            var i = { selector: this.last.transform.props.ref, transform: transform };
                            this.transforms.push(i);
                            return new Impl(i, this.transforms);
                        };
                        Impl.prototype.compile = function () {
                            return this.transforms;
                        };
                        return Impl;
                    }());
                    Builder.Impl = Impl;
                })(Builder = Transform.Builder || (Transform.Builder = {}));
            })(Transform = Tree.Transform || (Tree.Transform = {}));
        })(Tree = Bootstrap.Tree || (Bootstrap.Tree = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Interactivity;
        (function (Interactivity) {
            "use strict";
            var Info;
            (function (Info) {
                Info.empty = { kind: 0 /* Empty */ };
                function selection(source, elements) {
                    return { kind: 1 /* Selection */, source: source, elements: elements };
                }
                Info.selection = selection;
            })(Info = Interactivity.Info || (Interactivity.Info = {}));
            function isEmpty(info) {
                if (info.kind === 0 /* Empty */ || !info.source.tree)
                    return true;
                if (info.source.type.info.typeClass === Bootstrap.Entity.VisualClass && info.source.type === Bootstrap.Entity.Molecule.Visual) {
                    var modelOrSelection = Bootstrap.Utils.Molecule.findModelOrSelection(info.source);
                    if (modelOrSelection) {
                        if (!info.elements || !info.elements.length) {
                            return true;
                        }
                    }
                }
                return false;
            }
            Interactivity.isEmpty = isEmpty;
            function isSelection(info) {
                return info.kind === 1 /* Selection */ && !!info.source.tree;
            }
            Interactivity.isSelection = isSelection;
            function interactivityInfoEqual(a, b) {
                if (!a && !b)
                    return true;
                if (!a || !b)
                    return false;
                if (a.kind !== b.kind)
                    return false;
                if (a.kind === 0 /* Empty */)
                    return true;
                if (a.source !== b.source)
                    return false;
                var x = a.elements, y = b.elements;
                if (x.length !== y.length)
                    return false;
                for (var i = 0, _l = x.length; i < _l; i++) {
                    if (x[i] !== y[i])
                        return false;
                }
                return true;
            }
            Interactivity.interactivityInfoEqual = interactivityInfoEqual;
            function interactivitySelectionElementsEqual(a, b) {
                var x = a.elements, y = b.elements;
                if (x.length !== y.length)
                    return false;
                for (var i = 0, _l = x.length; i < _l; i++) {
                    if (x[i] !== y[i])
                        return false;
                }
                return true;
            }
            Interactivity.interactivitySelectionElementsEqual = interactivitySelectionElementsEqual;
        })(Interactivity = Bootstrap.Interactivity || (Bootstrap.Interactivity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Interactivity;
        (function (Interactivity) {
            "use strict";
            var HighlightManager = /** @class */ (function () {
                function HighlightManager(context) {
                    var _this = this;
                    this.context = context;
                    this.providers = [];
                    this.empty = [];
                    Bootstrap.Event.Visual.VisualHoverElement.getStream(context).subscribe(function (ev) { return Bootstrap.Event.Interactivity.Highlight.dispatch(context, _this.getInfo(ev.data)); });
                }
                HighlightManager.prototype.addProvider = function (provider) {
                    this.providers.push(provider);
                };
                HighlightManager.prototype.removeProvider = function (provider) {
                    this.providers = this.providers.filter(function (p) { return p !== provider; });
                    Bootstrap.Event.Interactivity.Highlight.dispatch(this.context, []);
                };
                HighlightManager.prototype.getInfo = function (i) {
                    if (!i)
                        return this.empty;
                    var info = [];
                    for (var _i = 0, _a = this.providers; _i < _a.length; _i++) {
                        var p = _a[_i];
                        var e = p.call(null, i);
                        if (e)
                            info.push(e);
                    }
                    return info;
                };
                return HighlightManager;
            }());
            Interactivity.HighlightManager = HighlightManager;
        })(Interactivity = Bootstrap.Interactivity || (Bootstrap.Interactivity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Interactivity;
        (function (Interactivity) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                function transformMoleculeAtomIndices(model, context, indices) {
                    var m = context.structure;
                    var _a = m.data.atoms, residueIndex = _a.residueIndex, chainIndex = _a.chainIndex, entityIndex = _a.entityIndex, name = _a.name, authName = _a.authName, id = _a.id, occupancy = _a.occupancy, tempFactor = _a.tempFactor, elementSymbol = _a.elementSymbol, altLoc = _a.altLoc;
                    var _b = m.positions, x = _b.x, y = _b.y, z = _b.z;
                    var _c = m.data.residues, resName = _c.name, resAuthName = _c.authName, seqNumber = _c.seqNumber, authSeqNumber = _c.authSeqNumber, insCode = _c.insCode, isHet = _c.isHet;
                    var _d = m.data.chains, asymId = _d.asymId, authAsymId = _d.authAsymId;
                    var entityId = m.data.entities.entityId;
                    var aI = -1, eI = -1, cI = -1, rI = -1;
                    var e, c, r, a;
                    var eP = function () { return e = { index: eI, entityId: entityId[eI] }; };
                    var cP = function () { return c = { index: cI, asymId: asymId[cI], authAsymId: authAsymId[cI], entity: e }; };
                    var rP = function () { return r = { index: rI, name: resName[rI], authName: resAuthName[rI], seqNumber: seqNumber[rI], authSeqNumber: authSeqNumber[rI], insCode: insCode[rI], isHet: isHet[rI], chain: c }; };
                    var aP = function () { return a = { index: aI, id: id[aI], name: name[aI], authName: authName[aI], elementSymbol: elementSymbol[aI], occupancy: occupancy[aI], tempFactor: tempFactor[aI], x: x[aI], y: y[aI], z: z[aI], altLoc: altLoc[aI], residue: r }; };
                    var entities = [];
                    var chains = [];
                    var residues = [];
                    var atoms = [];
                    for (var i = 0; i < indices.length; i++) {
                        aI = indices[i];
                        if (!context.hasAtom(aI))
                            continue;
                        if (eI !== entityIndex[aI]) {
                            eI = entityIndex[aI];
                            entities.push(eP());
                        }
                        if (cI !== chainIndex[aI]) {
                            cI = chainIndex[aI];
                            chains.push(cP());
                        }
                        if (rI !== residueIndex[aI]) {
                            rI = residueIndex[aI];
                            residues.push(rP());
                        }
                        atoms.push(aP());
                    }
                    return {
                        modelRef: model.ref,
                        moleculeId: m.id,
                        modelId: m.modelId,
                        atoms: atoms,
                        residues: residues,
                        chains: chains,
                        entities: entities
                    };
                }
                Molecule.transformMoleculeAtomIndices = transformMoleculeAtomIndices;
                function transformInteraction(info) {
                    if (Interactivity.isEmpty(info))
                        return void 0;
                    var modelOrSelection = Bootstrap.Utils.Molecule.findModelOrSelection(info.source);
                    if (!modelOrSelection)
                        return void 0;
                    var context = Bootstrap.Utils.Molecule.findQueryContext(modelOrSelection);
                    var model = Bootstrap.Utils.Molecule.findModel(modelOrSelection);
                    if (!context || !model)
                        return void 0;
                    return transformMoleculeAtomIndices(model, context, info.elements);
                }
                Molecule.transformInteraction = transformInteraction;
                function formatAtomExtra(a) {
                    var extras = [];
                    if (a.occupancy !== 1) {
                        extras.push("occupancy " + Bootstrap.Utils.round(a.occupancy, 2));
                    }
                    if (a.altLoc) {
                        extras.push("alt. loc " + a.altLoc);
                    }
                    if (!extras.length)
                        return '';
                    return " <small>[" + extras.join(', ') + "]</small>";
                }
                function formatAtom(a) {
                    return "<span><b>" + a.name + " " + a.elementSymbol + " " + a.id + "</b>" + formatAtomExtra(a) + " at (" + Bootstrap.Utils.round(a.x, 1) + ", " + Bootstrap.Utils.round(a.y, 1) + ", " + Bootstrap.Utils.round(a.z, 1) + ")</span>";
                }
                function formatAtomShort(a) {
                    return "<span>" + a.name + " " + a.elementSymbol + " " + a.id + formatAtomExtra(a) + "</span>";
                }
                function formatResidue(r) {
                    return "<span>" + r.authName + " " + r.chain.authAsymId + " " + r.authSeqNumber + (r.insCode !== null ? ' i: ' + r.insCode : '') + "</span>";
                }
                function formatMolecule(info) {
                    if (info.modelId === '1') {
                        return "<span><small>[" + info.moleculeId + "]</small></span>";
                    }
                    return "<span><small>[" + info.moleculeId + ":" + info.modelId + "]</small></span>";
                }
                function formatInfo(info) {
                    if (!info || !info.atoms.length)
                        return "";
                    if (info.atoms.length === 1) {
                        return "<span>" + formatAtom(info.atoms[0]) + " on <b><small>" + formatResidue(info.residues[0]) + "</small></b> " + formatMolecule(info) + "</span>";
                    }
                    else if (info.residues.length === 1) {
                        return "<span><b>" + formatResidue(info.residues[0]) + "</b> " + formatMolecule(info) + "</span>";
                    }
                    else {
                        return "<span><small>" + info.atoms.length + " atoms on</small> <b>" + info.residues.length + " residues</b> " + formatMolecule(info) + "</span>";
                    }
                }
                Molecule.formatInfo = formatInfo;
                function formatInfoShort(info) {
                    if (!info || !info.atoms.length)
                        return "";
                    if (info.atoms.length === 1) {
                        return "<span><b>" + formatAtomShort(info.atoms[0]) + "</b> " + formatMolecule(info) + "</span>";
                    }
                    else if (info.residues.length === 1) {
                        return "<span><b>" + formatResidue(info.residues[0]) + "</b> " + formatMolecule(info) + "</span>";
                    }
                    else {
                        return "<span><b>" + info.residues.length + " residues</b> " + formatMolecule(info) + "</span>";
                    }
                }
                Molecule.formatInfoShort = formatInfoShort;
                function isMoleculeModelInteractivity(info) {
                    if (Interactivity.isEmpty(info))
                        return false;
                    if (info.source.type.info.typeClass === Bootstrap.Entity.VisualClass && info.source.type !== Bootstrap.Entity.Molecule.Visual)
                        return false;
                    var modelOrSelection = Bootstrap.Utils.Molecule.findModelOrSelection(info.source);
                    if (!modelOrSelection)
                        return false;
                    return true;
                }
                Molecule.isMoleculeModelInteractivity = isMoleculeModelInteractivity;
            })(Molecule = Interactivity.Molecule || (Interactivity.Molecule = {}));
        })(Interactivity = Bootstrap.Interactivity || (Bootstrap.Interactivity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            "use strict";
            var DisplayList = /** @class */ (function () {
                function DisplayList(context, scene) {
                    var _this = this;
                    this.context = context;
                    this.scene = scene;
                    this.entries = new Map();
                    this.originalThemes = new Map();
                    this.lastParent = NaN;
                    Bootstrap.Event.Tree.NodeAdded.getStream(context).subscribe(function (e) {
                        if (!Bootstrap.Entity.isClass(e.data, Bootstrap.Entity.VisualClass))
                            return;
                        _this.add(e.data);
                    });
                    Bootstrap.Event.Tree.NodeRemoved.getStream(context).subscribe(function (e) {
                        if (!Bootstrap.Entity.isClass(e.data, Bootstrap.Entity.VisualClass))
                            return;
                        _this.remove(e.data);
                    });
                    Bootstrap.Event.Tree.NodeUpdated.getStream(context).subscribe(function (e) {
                        if (!Bootstrap.Entity.isVisual(e.data))
                            return;
                        var m = _this.entries.get(e.data.id);
                        if (!m)
                            return;
                        var vis = m.visual.state.visibility !== 2 /* None */;
                        if (m.visual.props.model.getVisibility() !== vis) {
                            m.visual.props.model.updateVisibility(vis);
                        }
                    });
                    Bootstrap.Command.Visual.UpdateBasicTheme.getStream(context).subscribe(function (e) {
                        if (!_this.entries.get(e.data.visual.id) || !Bootstrap.Entity.isVisual(e.data.visual))
                            return;
                        var v = e.data.visual;
                        if (e.data.theme.isSticky) {
                            _this.originalThemes.set(v.id, e.data.theme);
                        }
                        else if (!_this.originalThemes.get(v.id)) {
                            _this.originalThemes.set(v.id, v.props.model.theme);
                        }
                        v.props.model.applyTheme(e.data.theme);
                    });
                    Bootstrap.Command.Molecule.Highlight.getStream(context).subscribe(function (e) { return _this.highlightMoleculeModel(e.data); });
                    Bootstrap.Command.Visual.ResetTheme.getStream(context).subscribe(function (e) { return _this.resetThemesAndHighlight(e.data && e.data.selection); });
                }
                DisplayList.prototype.isEmpty = function () {
                    return !this.entries.size;
                };
                DisplayList.prototype.add = function (v) {
                    if (this.entries.has(v.id) || !v.props.model)
                        return false;
                    var parentId = v.parent.id;
                    this.entries.set(v.id, { visual: v, parentId: parentId });
                    this.scene.scene.models.add(v.props.model, this.entries.size === 1 && this.lastParent !== parentId);
                    var vis = v.state.visibility !== 2 /* None */;
                    if (v.props.model.getVisibility() !== vis) {
                        v.props.model.updateVisibility(vis);
                    }
                    v.props.model.tag = v;
                    return true;
                };
                DisplayList.prototype.remove = function (v) {
                    if (!this.entries.has(v.id))
                        return false;
                    this.lastParent = this.entries.get(v.id).parentId;
                    this.entries.delete(v.id);
                    this.originalThemes.delete(v.id);
                    this.scene.scene.models.removeAndDispose(v.props.model);
                    v.props.model.tag = void 0;
                    v.props.model = void 0;
                    return true;
                };
                DisplayList.prototype.get = function (id) {
                    return this.entries.get(id);
                };
                DisplayList.prototype.resetThemesAndHighlight = function (sel) {
                    var _this = this;
                    if (!sel) {
                        this.originalThemes.forEach(function (t, id) {
                            var model = _this.entries.get(id).visual.props.model;
                            if (!model.theme.isSticky) {
                                model.applyTheme(t);
                                _this.originalThemes.delete(id);
                            }
                            else {
                                _this.originalThemes.set(id, model.theme);
                            }
                        });
                        this.entries.forEach(function (v) { return v.visual.props.model.highlight(false); });
                        this.scene.scene.forceRender();
                        return;
                    }
                    var es = this.context.select(sel);
                    for (var _i = 0, es_1 = es; _i < es_1.length; _i++) {
                        var e = es_1[_i];
                        if (!Bootstrap.Entity.isVisual(e) || !this.originalThemes.has(e.id))
                            continue;
                        var v = e;
                        var t = this.originalThemes.get(v.id);
                        var model = v.props.model;
                        if (!model.theme.isSticky) {
                            model.applyTheme(t);
                            this.originalThemes.delete(v.id);
                        }
                        else {
                            this.originalThemes.set(v.id, model.theme);
                        }
                        model.highlight(false);
                    }
                    this.scene.scene.forceRender();
                };
                DisplayList.prototype.highlightMoleculeModel = function (what) {
                    var _this = this;
                    var model = Bootstrap.Utils.Molecule.findModel(what.model);
                    if (!model) {
                        console.warn('Highlight: Trying to highlight a non-molecule model entity, ignoring...');
                        return;
                    }
                    var targets = [];
                    this.context.select(Bootstrap.Tree.Selection.byValue(what.model).subtree()).forEach(function (n) {
                        if (Bootstrap.Entity.isVisual(n) && _this.entries.get(n.id))
                            targets.push(n);
                    });
                    if (!targets.length)
                        return;
                    var q = Bootstrap.Utils.Molecule.getModelAndIndicesFromQuery(model, what.query);
                    if (!q || !q.indices.length)
                        return;
                    var action = what.isOn ? 3 /* Highlight */ : 4 /* RemoveHighlight */;
                    for (var _i = 0, targets_1 = targets; _i < targets_1.length; _i++) {
                        var t = targets_1[_i];
                        t.props.model.applySelection(q.indices, action);
                    }
                };
                return DisplayList;
            }());
            Visualization.DisplayList = DisplayList;
            var SceneWrapper = /** @class */ (function () {
                function SceneWrapper(element, context, options) {
                    var _this = this;
                    this.context = context;
                    this._destroyed = false;
                    this.cameraChanged = new Bootstrap.Rx.Subject();
                    this.cameraObserver = function (c) { return _this.cameraChanged.onNext(c); };
                    this.models = new DisplayList(context, this);
                    this.scene = new LiteMol.Visualization.Scene(element, options);
                    this.scene.camera.observe(this.cameraObserver);
                    this.scene.events.addEventListener('hover', function (e) { return _this.handleEvent(e, Bootstrap.Event.Visual.VisualHoverElement); });
                    this.scene.events.addEventListener('select', function (e) { return _this.handleEvent(e, Bootstrap.Event.Visual.VisualSelectElement); });
                    this.cameraChanged.throttle(1000 / 30).subscribe(function (c) {
                        Bootstrap.Event.Visual.CameraChanged.dispatch(_this.context, c);
                    });
                    Bootstrap.Command.Entity.Focus.getStream(context)
                        .subscribe(function (e) {
                        var _a;
                        if (e.data.length === 1) {
                            var t = e.data[0];
                            if (Bootstrap.Entity.isMoleculeSelection(t)) {
                                _this.focusMoleculeModelSelection(t);
                            }
                            else if (Bootstrap.Entity.isClass(t, Bootstrap.Entity.VisualClass)) {
                                _this.scene.camera.focusOnModel(t.props.model);
                            }
                        }
                        else {
                            (_a = _this.scene.camera).focusOnModel.apply(_a, e.data.filter(function (e) { return Bootstrap.Entity.isClass(e, Bootstrap.Entity.VisualClass); }).map(function (e) { return e.props.model; }));
                        }
                    });
                    Bootstrap.Command.Entity.Highlight.getStream(context)
                        .subscribe(function (e) {
                        for (var _i = 0, _a = e.data.entities; _i < _a.length; _i++) {
                            var v = _a[_i];
                            if (!Bootstrap.Entity.isClass(v, Bootstrap.Entity.VisualClass) || !v.props.model)
                                continue;
                            v.props.model.highlight(e.data.isOn);
                        }
                    });
                    Bootstrap.Command.Visual.ResetScene.getStream(context).subscribe(function (e) { return _this.resetScene(); });
                    Bootstrap.Command.Molecule.FocusQuery.getStream(context).subscribe(function (e) { return _this.focusMoleculeModelOnQuery(e.data); });
                }
                SceneWrapper.prototype.resetScene = function () {
                    if (this._destroyed)
                        return;
                    Bootstrap.Event.Visual.VisualSelectElement.dispatch(this.context, Bootstrap.Interactivity.Info.empty);
                    this.models.resetThemesAndHighlight();
                    this.scene.camera.reset();
                };
                Object.defineProperty(SceneWrapper.prototype, "camera", {
                    get: function () {
                        return this.scene.camera;
                    },
                    enumerable: true,
                    configurable: true
                });
                SceneWrapper.prototype.destroy = function () {
                    if (this._destroyed)
                        return;
                    this.scene.camera.stopObserving(this.cameraObserver);
                    this.scene.destroy();
                    this.scene = void 0;
                    this._destroyed = true;
                };
                SceneWrapper.prototype.handleEvent = function (e, event) {
                    var data = e.data;
                    if (data && data.model && data.elements) {
                        event.dispatch(this.context, Bootstrap.Interactivity.Info.selection(data.model.tag, data.elements));
                    }
                    else {
                        event.dispatch(this.context, Bootstrap.Interactivity.Info.empty);
                    }
                };
                SceneWrapper.prototype.focusMoleculeModelSelection = function (sel) {
                    if (!Bootstrap.Tree.Node.is(sel, Bootstrap.Entity.Molecule.Selection)) {
                        console.warn('Focus: Trying to focus on non-molecule selection, ignoring...');
                        return;
                    }
                    var model = Bootstrap.Utils.Molecule.findModel(sel);
                    if (!model) {
                        console.warn('Focus: Molecule model for selection not found, ignoring...');
                        return;
                    }
                    var center = LiteMol.Core.Geometry.LinearAlgebra.Vector3.zero();
                    var r = Bootstrap.Utils.Molecule.getCentroidAndRadius(model.props.model, sel.props.indices, center);
                    this.scene.camera.focusOnPoint(LiteMol.Core.Geometry.LinearAlgebra.Vector3.toObj(center), r);
                };
                SceneWrapper.prototype.focusMoleculeModelOnQuery = function (what) {
                    var q = Bootstrap.Utils.Molecule.getModelAndIndicesFromQuery(what.model, what.query);
                    if (!q || !q.indices.length)
                        return;
                    var center = LiteMol.Core.Geometry.LinearAlgebra.Vector3.zero();
                    var r = Bootstrap.Utils.Molecule.getCentroidAndRadius(q.model.props.model, q.indices, center);
                    this.scene.camera.focusOnPoint(LiteMol.Core.Geometry.LinearAlgebra.Vector3.toObj(center), r);
                };
                return SceneWrapper;
            }());
            Visualization.SceneWrapper = SceneWrapper;
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            "use strict";
            var Style;
            (function (Style) {
                function getTaskType(style) {
                    return !style.taskType ? 'Normal' : style.taskType;
                }
                Style.getTaskType = getTaskType;
                function create(style) {
                    return style;
                }
                Style.create = create;
            })(Style = Visualization.Style || (Visualization.Style = {}));
            var Theme;
            (function (Theme) {
                function getProps(theme) {
                    var colors = LiteMol.Core.Utils.FastMap.create();
                    if (theme.colors)
                        theme.colors.forEach(function (c, n) { return colors.set(n, c); });
                    var variables = LiteMol.Core.Utils.FastMap.create();
                    if (theme.variables)
                        theme.variables.forEach(function (c, n) { return variables.set(n, c); });
                    return {
                        colors: colors,
                        variables: variables,
                        transparency: theme.transparency,
                        interactive: theme.interactive,
                        disableFog: theme.disableFog,
                        isSticky: true
                    };
                }
                Theme.getProps = getProps;
            })(Theme = Visualization.Theme || (Visualization.Theme = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                var Vis = LiteMol.Visualization;
                Molecule.UniformBaseColors = Bootstrap.Immutable.Map({
                    'Uniform': Vis.Theme.Default.UniformColor,
                    'Highlight': Vis.Theme.Default.HighlightColor,
                    'Selection': Vis.Theme.Default.SelectionColor,
                });
                Molecule.ModelVisualBaseColors = Bootstrap.Immutable.Map({
                    'Bond': Vis.Molecule.Colors.DefaultBondColor,
                    'Highlight': Vis.Theme.Default.HighlightColor,
                    'Selection': Vis.Theme.Default.SelectionColor,
                });
                function mappingClosure(index, property) {
                    return function (i) { return property[index[i]]; };
                }
                function createPaletteThemeProvider(provider, pallete) {
                    return function (e, props) {
                        var model = Bootstrap.Utils.Molecule.findModel(e).props.model;
                        var map = provider(model);
                        var mapping = Vis.Theme.createPalleteMapping(mappingClosure(map.index, map.property), pallete);
                        return Vis.Theme.createMapping(mapping, props);
                    };
                }
                Molecule.createPaletteThemeProvider = createPaletteThemeProvider;
                function createCachedPaletteThemeProvider(name, provider, pallete) {
                    return function (e, props) {
                        var modelE = Bootstrap.Utils.Molecule.findModel(e);
                        var ctx = modelE.tree && modelE.tree.context;
                        if (ctx) {
                            var mapping_1 = ctx.entityCache.get(modelE, 'theme-mapping-' + name);
                            if (mapping_1) {
                                return Vis.Theme.createMapping(mapping_1, props);
                            }
                        }
                        var model = modelE.props.model;
                        var map = provider(model);
                        var mapping = Vis.Theme.createPalleteMapping(mappingClosure(map.index, map.property), pallete);
                        if (ctx)
                            ctx.entityCache.set(e, 'theme-mapping-' + name, mapping);
                        return Vis.Theme.createMapping(mapping, props);
                    };
                }
                Molecule.createCachedPaletteThemeProvider = createCachedPaletteThemeProvider;
                function uniformThemeProvider(e, props) {
                    if (props && props.colors) {
                        if (!props.colors.get('Bond') && props.colors.get('Uniform')) {
                            var oldColors = props.colors;
                            props = Bootstrap.Utils.assign({}, props);
                            var newColors_1 = LiteMol.Core.Utils.FastMap.create();
                            props.colors = newColors_1;
                            oldColors.forEach(function (color, key) { return newColors_1.set(key, color); });
                            newColors_1.set('Bond', props.colors.get('Uniform'));
                        }
                    }
                    return Vis.Theme.createUniform(props);
                }
                Molecule.uniformThemeProvider = uniformThemeProvider;
                function createColorMapThemeProvider(provider, colorMap, fallbackColor) {
                    return function (e, props) {
                        var modelE = Bootstrap.Utils.Molecule.findModel(e);
                        var model = modelE.props.model;
                        var map = provider(model);
                        var mapping = Vis.Theme.createColorMapMapping(mappingClosure(map.index, map.property), colorMap, fallbackColor);
                        return Vis.Theme.createMapping(mapping, props);
                    };
                }
                Molecule.createColorMapThemeProvider = createColorMapThemeProvider;
                function createCachedColorMapThemeProvider(name, provider, colorMap, fallbackColor) {
                    return function (e, props) {
                        var modelE = Bootstrap.Utils.Molecule.findModel(e);
                        var ctx = modelE.tree && modelE.tree.context;
                        if (ctx) {
                            var mapping_2 = ctx.entityCache.get(modelE, 'theme-mapping-map-' + name);
                            if (mapping_2) {
                                return Vis.Theme.createMapping(mapping_2, props);
                            }
                        }
                        var model = modelE.props.model;
                        var map = provider(model);
                        var mapping = Vis.Theme.createColorMapMapping(mappingClosure(map.index, map.property), colorMap, fallbackColor);
                        if (ctx)
                            ctx.entityCache.set(e, 'theme-mapping-map-' + name, mapping);
                        return Vis.Theme.createMapping(mapping, props);
                    };
                }
                Molecule.createCachedColorMapThemeProvider = createCachedColorMapThemeProvider;
                var RainbowMapping = /** @class */ (function () {
                    function RainbowMapping(model, _a) {
                        var r = _a.r, g = _a.g, b = _a.b;
                        this.residueIndex = model.data.atoms.residueIndex;
                        this.r = r;
                        this.g = g;
                        this.b = b;
                    }
                    RainbowMapping.prototype.getProperty = function (index) { return this.residueIndex[index]; };
                    RainbowMapping.prototype.setColor = function (i, color) {
                        color.r = this.r[i];
                        color.g = this.g[i];
                        color.b = this.b[i];
                    };
                    return RainbowMapping;
                }());
                Molecule.RainbowPalette = [
                    Vis.Color.fromHex(0xCC2200),
                    Vis.Color.fromHex(0xCC7700),
                    Vis.Color.fromHex(0xCCAA00),
                    Vis.Color.fromHex(0x00CC00),
                    Vis.Color.fromHex(0x00AACC),
                    Vis.Color.fromHex(0x0000CC),
                    Vis.Color.fromHex(0x892AD2),
                    Vis.Color.fromHex(0xB77CE3)
                ];
                var RainbowBaseColors = Bootstrap.Immutable.Map({
                    'Bond': Vis.Molecule.Colors.DefaultBondColor,
                    'Highlight': Vis.Color.fromHex(0xFFFFFF),
                    'Selection': Vis.Color.fromHex(0x968000),
                });
                function makeRainbow(model, groupsSource, groupId) {
                    var rC = model.data.residues.count;
                    var _a = { r: new Float32Array(rC), g: new Float32Array(rC), b: new Float32Array(rC) }, r = _a.r, g = _a.g, b = _a.b;
                    var groups = groupsSource(model);
                    var count = groups.count, residueStartIndex = groups.residueStartIndex, residueEndIndex = groups.residueEndIndex;
                    var cC = Molecule.RainbowPalette.length - 1;
                    var color = Vis.Color.fromHex(0);
                    var strips = LiteMol.Core.Utils.FastMap.create();
                    for (var cI = 0; cI < count; cI++) {
                        var id = groupId(groups, cI);
                        var l = residueEndIndex[cI] - residueStartIndex[cI];
                        if (strips.has(id)) {
                            strips.get(id).count += l;
                        }
                        else {
                            strips.set(id, { index: 0, count: l });
                        }
                    }
                    strips.forEach(function (s) { return s.count = Math.max(s.count - 1, 1); });
                    for (var cI = 0; cI < count; cI++) {
                        var s = residueStartIndex[cI], l = residueEndIndex[cI] - s;
                        var strip = strips.get(groupId(groups, cI));
                        var max = strip.count;
                        for (var i = 0; i < l; i++) {
                            var t = cC * strip.index / max;
                            var low = Math.floor(t), high = Math.ceil(t);
                            Vis.Color.interpolate(Molecule.RainbowPalette[low], Molecule.RainbowPalette[high], t - low, color);
                            r[s + i] = color.r;
                            g[s + i] = color.g;
                            b[s + i] = color.b;
                            strip.index++;
                        }
                    }
                    return { r: r, g: g, b: b };
                }
                function createRainbowProvider(groups, groupId) {
                    return function (e, props) {
                        var model = Bootstrap.Utils.Molecule.findModel(e).props.model;
                        var colors = makeRainbow(model, groups, groupId);
                        var mapping = new RainbowMapping(model, colors);
                        return Vis.Theme.createMapping(mapping, props);
                    };
                }
                var Default;
                (function (Default) {
                    Default.Themes = [
                        {
                            name: 'Chain ID',
                            description: 'Color the surface by Chain ID.',
                            colors: Molecule.ModelVisualBaseColors,
                            provider: createCachedPaletteThemeProvider('chain-id', function (m) { return ({ index: m.data.atoms.residueIndex, property: m.data.residues.asymId }); }, Vis.Molecule.Colors.DefaultPallete)
                        }, {
                            name: 'Entity ID',
                            description: 'Color the surface by Entity ID.',
                            colors: Molecule.ModelVisualBaseColors,
                            provider: createPaletteThemeProvider(function (m) { return ({ index: m.data.atoms.residueIndex, property: m.data.residues.entityId }); }, Vis.Molecule.Colors.DefaultPallete)
                        }, {
                            name: 'Entity Type',
                            description: 'Color the surface by Entity Type.',
                            colors: Molecule.ModelVisualBaseColors,
                            provider: createPaletteThemeProvider(function (m) { return ({ index: m.data.atoms.entityIndex, property: m.data.entities.type }); }, Vis.Molecule.Colors.DefaultPallete)
                        }, {
                            name: 'Residue Name',
                            description: 'Color the surface by residue name.',
                            colors: Molecule.ModelVisualBaseColors,
                            provider: createPaletteThemeProvider(function (m) { return ({ index: m.data.atoms.residueIndex, property: m.data.residues.name }); }, Vis.Molecule.Colors.DefaultPallete)
                        }, {
                            name: 'Element Symbol',
                            description: 'Color the surface by atom elemnt symbol.',
                            colors: Molecule.ModelVisualBaseColors,
                            provider: createColorMapThemeProvider(function (m) { return ({ index: m.data.atoms.indices, property: m.data.atoms.elementSymbol }); }, Vis.Molecule.Colors.DefaultElementColorMap, Vis.Molecule.Colors.DefaultElementColor)
                        }, {
                            name: 'Rainbow (Chain)',
                            description: 'Color each chain using rainbow palette.',
                            colors: RainbowBaseColors,
                            provider: createRainbowProvider(function (m) { return m.data.chains; }, function (t, i) { return t.asymId[i] + " " + t.entityId[i]; })
                        }, {
                            name: 'Rainbow (Entity)',
                            description: 'Color each entity using rainbow palette.',
                            colors: RainbowBaseColors,
                            provider: createRainbowProvider(function (m) { return m.data.entities; }, function (t, i) { return t.entityId[i]; })
                        }, {
                            name: 'Uniform Color',
                            description: 'Same color everywhere.',
                            colors: Molecule.UniformBaseColors,
                            provider: uniformThemeProvider
                        }
                    ];
                    Default.CartoonThemeTemplate = Default.Themes.filter(function (t) { return t.name === 'Chain ID'; })[0];
                    Default.ElementSymbolThemeTemplate = Default.Themes.filter(function (t) { return t.name === 'Element Symbol'; })[0];
                    Default.SurfaceThemeTemplate = Default.Themes.filter(function (t) { return t.name === 'Uniform Color'; })[0];
                    Default.UniformThemeTemplate = Default.Themes.filter(function (t) { return t.name === 'Uniform Color'; })[0];
                    Default.RainbowEntityThemeTemplate = Default.Themes.filter(function (t) { return t.name === 'Rainbow (Entity)'; })[0];
                })(Default = Molecule.Default || (Molecule.Default = {}));
            })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                Molecule.TypeDescriptions = {
                    'Cartoons': { label: 'Cartoon', shortLabel: 'Cartoon' },
                    'Calpha': { label: 'C-\u03B1 Trace', shortLabel: 'C-\u03B1' },
                    'BallsAndSticks': { label: 'Balls and Sticks', shortLabel: "B'n'S" },
                    'VDWBalls': { label: 'VDW Balls', shortLabel: 'VDW' },
                    'Surface': { label: 'Surface', shortLabel: 'Surface' }
                };
                Molecule.Types = ['Cartoons', 'Calpha', 'BallsAndSticks', 'VDWBalls', 'Surface'];
                Molecule.DetailTypes = ['Automatic', 'Very Low', 'Low', 'Medium', 'High', 'Very High'];
                var Default;
                (function (Default) {
                    Default.DetailParams = { detail: 'Automatic' };
                    Default.CartoonParams = {
                        showDirectionCone: false,
                        detail: 'Automatic'
                    };
                    Default.BallsAndSticksParams = {
                        useVDW: true,
                        vdwScaling: 0.22,
                        atomRadius: 0.35,
                        bondRadius: 0.09,
                        hideHydrogens: false,
                        customMaxBondLengths: void 0,
                        detail: 'Automatic'
                    };
                    Default.SurfaceParams = {
                        probeRadius: 0.4,
                        automaticDensity: true,
                        density: 1.1,
                        smoothing: 10,
                        isWireframe: false
                    };
                    Default.Transparency = { alpha: 1.0, writeDepth: false };
                    Default.ForType = (function () {
                        var types = {
                            'Cartoons': { type: 'Cartoons', params: Default.CartoonParams, theme: { template: Default.CartoonThemeTemplate, colors: Default.CartoonThemeTemplate.colors, transparency: Default.Transparency, interactive: true } },
                            'Calpha': { type: 'Calpha', params: { detail: 'Automatic' }, theme: { template: Default.CartoonThemeTemplate, colors: Default.CartoonThemeTemplate.colors, transparency: Default.Transparency, interactive: true } },
                            'BallsAndSticks': { type: 'BallsAndSticks', params: Default.BallsAndSticksParams, theme: { template: Default.ElementSymbolThemeTemplate, colors: Default.ElementSymbolThemeTemplate.colors, transparency: Default.Transparency, interactive: true } },
                            'VDWBalls': { type: 'VDWBalls', params: { detail: 'Automatic' }, theme: { template: Default.ElementSymbolThemeTemplate, colors: Default.ElementSymbolThemeTemplate.colors, transparency: Default.Transparency, interactive: true } },
                            'Surface': { type: 'Surface', params: Default.SurfaceParams, theme: { template: Default.SurfaceThemeTemplate, colors: Default.SurfaceThemeTemplate.colors, transparency: { alpha: 0.33, writeDepth: false }, interactive: true } }
                        };
                        var map = new Map();
                        for (var _i = 0, _a = Object.keys(types); _i < _a.length; _i++) {
                            var k = _a[_i];
                            map.set(k, types[k]);
                        }
                        return map;
                    })();
                })(Default = Molecule.Default || (Molecule.Default = {}));
            })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                var Vis = LiteMol.Visualization;
                var MolVis = LiteMol.Visualization.Molecule;
                function getTessalation(type, count) {
                    if (type === 'Automatic') {
                        if (count < 250)
                            return 5;
                        if (count < 1000)
                            return 4;
                        if (count < 75000)
                            return 3;
                        if (count < 250000)
                            return 2;
                        if (count < 600000)
                            return 1;
                        return 0;
                    }
                    var d = Molecule.DetailTypes.indexOf(type) - 1;
                    return Math.max(d, 0);
                }
                function getSurfaceDensity(params, model, indices) {
                    if (!!params.automaticDensity) {
                        var _a = Bootstrap.Utils.Molecule.getBox(model, indices, 0), bottomLeft = _a.bottomLeft, topRight = _a.topRight;
                        var box = LiteMol.Core.Geometry.LinearAlgebra.Vector3.sub(topRight, topRight, bottomLeft);
                        var density = Math.pow(((Math.pow(99, 3)) / (box[0] * box[1] * box[2])), (1 / 3));
                        if (density > 1.2)
                            return 1.2;
                        if (density < 0.1)
                            return 0.1;
                        return density;
                    }
                    if (params.density !== void 0)
                        return +params.density;
                    return 1.0;
                }
                function createCartoonParams(tessalation, isAlphaTrace, showCones) {
                    return {
                        tessalation: tessalation,
                        drawingType: isAlphaTrace
                            ? MolVis.Cartoons.CartoonsModelType.AlphaTrace
                            : MolVis.Cartoons.CartoonsModelType.Default,
                        showDirectionCones: showCones
                    };
                }
                function makeRadiusFunc(model, parameters) {
                    if (typeof parameters.vdwScaling === 'undefined')
                        parameters.vdwScaling = Molecule.Default.BallsAndSticksParams.vdwScaling;
                    if (typeof parameters.atomRadius === 'undefined')
                        parameters.atomRadius = Molecule.Default.BallsAndSticksParams.atomRadius;
                    if (!parameters.useVDW) {
                        return function (r) {
                            return function () { return r; };
                        }(parameters.atomRadius);
                    }
                    var vdw = Bootstrap.Utils.vdwRadiusFromElementSymbol(model);
                    return function (s, vdw) {
                        return function (i) {
                            return s * vdw(i);
                        };
                    }(parameters.vdwScaling, vdw);
                }
                function createBallsAndSticksParams(tessalation, model, parameters) {
                    var customMaxBondLengths = void 0;
                    if (parameters.customMaxBondLengths) {
                        var keys = Object.getOwnPropertyNames(parameters.customMaxBondLengths);
                        if (keys.length > 0)
                            customMaxBondLengths = LiteMol.Core.Utils.FastMap.create();
                        for (var _i = 0, keys_3 = keys; _i < keys_3.length; _i++) {
                            var key = keys_3[_i];
                            customMaxBondLengths.set(key, parameters.customMaxBondLengths[key]);
                        }
                    }
                    return {
                        tessalation: tessalation,
                        bondRadius: parameters.bondRadius,
                        hideBonds: false,
                        hideHydrogens: !!parameters.hideHydrogens,
                        atomRadius: makeRadiusFunc(model, parameters),
                        customMaxBondLengths: customMaxBondLengths
                    };
                }
                function createVDWBallsParams(tessalation, model) {
                    return {
                        tessalation: tessalation,
                        bondRadius: 0,
                        hideBonds: true,
                        atomRadius: Bootstrap.Utils.vdwRadiusFromElementSymbol(model)
                    };
                }
                function createModel(source, style, theme) {
                    var model = Bootstrap.Utils.Molecule.findModel(source).props.model;
                    var atomIndices = Bootstrap.Entity.isMoleculeModel(source) ? source.props.model.data.atoms.indices : source.props.indices;
                    if (!atomIndices.length)
                        return void 0;
                    var tessalation = getTessalation(style.params.detail, atomIndices.length);
                    switch (style.type) {
                        case 'Cartoons':
                            return MolVis.Cartoons.Model.create(source, { model: model, atomIndices: atomIndices, theme: theme, queryContext: Bootstrap.Utils.Molecule.findQueryContext(source), params: createCartoonParams(tessalation, false, style.params.showDirectionCone) });
                        case 'Calpha':
                            return MolVis.Cartoons.Model.create(source, { model: model, atomIndices: atomIndices, theme: theme, queryContext: Bootstrap.Utils.Molecule.findQueryContext(source), params: createCartoonParams(tessalation, true, style.params.showDirectionCone) });
                        case 'BallsAndSticks':
                            return Vis.Molecule.BallsAndSticks.Model.create(source, { model: model, atomIndices: atomIndices, theme: theme, params: createBallsAndSticksParams(tessalation, model, style.params) });
                        case 'VDWBalls':
                            return Vis.Molecule.BallsAndSticks.Model.create(source, { model: model, atomIndices: atomIndices, theme: theme, params: createVDWBallsParams(tessalation, model) });
                        default:
                            return void 0;
                    }
                }
                function createStandardVisual(source, transform, style) {
                    var _this = this;
                    return Bootstrap.Task.create("Visual (" + source.props.label + ")", Visualization.Style.getTaskType(style), function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var label, theme, mc, model;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    label = Molecule.TypeDescriptions[style.type].label;
                                    return [4 /*yield*/, ctx.updateProgress("Creating " + label + "...")];
                                case 1:
                                    _a.sent();
                                    theme = style.theme.template.provider(Bootstrap.Utils.Molecule.findModel(source), Visualization.Theme.getProps(style.theme));
                                    mc = createModel(source, style, theme);
                                    if (!mc) {
                                        throw 'Invalid input parameters.';
                                    }
                                    return [4 /*yield*/, mc.run(ctx)];
                                case 2:
                                    model = _a.sent();
                                    return [2 /*return*/, Bootstrap.Entity.Molecule.Visual.create(transform, { label: label, model: model, style: style, isSelectable: !style.isNotSelectable })];
                            }
                        });
                    }); });
                }
                function createSurface(source, transform, style) {
                    var _this = this;
                    return Bootstrap.Task.create("Molecular Surface (" + source.props.label + ")", Visualization.Style.getTaskType(style), function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var model, atomIndices, params, data, theme, surfaceModel, eLabel;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    model = Bootstrap.Utils.Molecule.findModel(source).props.model;
                                    atomIndices = Bootstrap.Entity.isMoleculeModel(source) ? source.props.model.data.atoms.indices : source.props.indices;
                                    params = style.params;
                                    return [4 /*yield*/, LiteMol.Core.Geometry.MolecularSurface.computeMolecularSurfaceAsync({
                                            positions: model.positions,
                                            atomIndices: atomIndices,
                                            parameters: {
                                                atomRadius: Bootstrap.Utils.vdwRadiusFromElementSymbol(model),
                                                density: getSurfaceDensity(params, model, atomIndices),
                                                probeRadius: params.probeRadius,
                                                smoothingIterations: params.smoothing,
                                                interactive: true
                                            }
                                        }).run(ctx)];
                                case 1:
                                    data = _a.sent();
                                    theme = style.theme.template.provider(Bootstrap.Utils.Molecule.findModel(source), Visualization.Theme.getProps(style.theme));
                                    return [4 /*yield*/, ctx.updateProgress('Creating visual...')];
                                case 2:
                                    _a.sent();
                                    return [4 /*yield*/, LiteMol.Visualization.Surface.Model.create(source, { surface: data.surface, theme: theme, parameters: { isWireframe: style.params.isWireframe } }).run(ctx)];
                                case 3:
                                    surfaceModel = _a.sent();
                                    eLabel = "Surface, " + Bootstrap.Utils.round(params.probeRadius, 2) + " \u212B probe";
                                    return [2 /*return*/, Bootstrap.Entity.Molecule.Visual.create(transform, { label: eLabel, model: surfaceModel, style: style, isSelectable: !style.isNotSelectable })];
                            }
                        });
                    }); });
                }
                function create(source, transform, style) {
                    if (style.type === 'Surface')
                        return createSurface(source, transform, style);
                    return createStandardVisual(source, transform, style);
                }
                Molecule.create = create;
            })(Molecule = Visualization.Molecule || (Visualization.Molecule = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Labels;
            (function (Labels) {
                "use strict";
                function createMoleculeLabels(parent, transform, style) {
                    var _this = this;
                    return Bootstrap.Task.create('Labels', 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var params, theme, labelsParams, model;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    params = style.params;
                                    theme = style.theme.template.provider(parent, Visualization.Theme.getProps(style.theme));
                                    labelsParams = Bootstrap.Utils.Molecule.create3DLabelsParams(parent, params, theme);
                                    return [4 /*yield*/, ctx.updateProgress('Creating labels...')];
                                case 1:
                                    _a.sent();
                                    return [4 /*yield*/, LiteMol.Visualization.Labels.Model.create(parent, labelsParams).run(ctx)];
                                case 2:
                                    model = _a.sent();
                                    return [2 /*return*/, Bootstrap.Entity.Visual.Labels.create(transform, { label: 'Labels', model: model, style: style, isSelectable: false })];
                            }
                        });
                    }); });
                }
                Labels.createMoleculeLabels = createMoleculeLabels;
                function createGenericLabels(parent, transform, params) {
                    var _this = this;
                    return Bootstrap.Task.create('Labels', 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var theme, labelsParams, model;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, ctx.updateProgress('Creating labels...')];
                                case 1:
                                    _a.sent();
                                    theme = params.style.theme.template.provider(parent, Visualization.Theme.getProps(params.style.theme));
                                    labelsParams = {
                                        positions: params.positions,
                                        sizes: params.sizes,
                                        labels: params.labels,
                                        options: params.options,
                                        theme: theme
                                    };
                                    return [4 /*yield*/, LiteMol.Visualization.Labels.Model.create(parent, labelsParams).run(ctx)];
                                case 2:
                                    model = _a.sent();
                                    return [2 /*return*/, Bootstrap.Entity.Visual.Labels.create(transform, { label: 'Labels', model: model, style: params.style, isSelectable: false })];
                            }
                        });
                    }); });
                }
                Labels.createGenericLabels = createGenericLabels;
            })(Labels = Visualization.Labels || (Visualization.Labels = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Labels;
            (function (Labels) {
                "use strict";
                var Style;
                (function (Style) {
                    function moleculeHasOnlyThemeChanged(oldS, newS) {
                        return Bootstrap.Utils.deepEqual(oldS.params, newS.params);
                    }
                    Style.moleculeHasOnlyThemeChanged = moleculeHasOnlyThemeChanged;
                    function createMoleculeStyle(params) {
                        return {
                            type: 'Labels',
                            params: {
                                kind: params.kind,
                                labelsOptions: params.labelsOptions ? params.labelsOptions : Default.MoleculeLabels.params.labelsOptions
                            },
                            theme: params.theme ? params.theme : Default.MoleculeLabels.theme,
                        };
                    }
                    Style.createMoleculeStyle = createMoleculeStyle;
                })(Style = Labels.Style || (Labels.Style = {}));
                var Default;
                (function (Default) {
                    var Vis = LiteMol.Visualization;
                    var uniformColors = Bootstrap.Immutable.Map({
                        'Uniform': Vis.Color.fromHexString('#eaeaea'),
                        'Background': Vis.Color.fromHexString('#777777'),
                        'Outline': Vis.Color.fromHexString('#333333')
                    });
                    var uniformVariables = Bootstrap.Immutable.Map({
                        'xOffset': 0.0,
                        'yOffset': 0.0,
                        'zOffset': 0.6,
                        'sizeFactor': 1.5,
                        'backgroundOpacity': 0.0,
                        'outlineWidth': 0.1
                    });
                    function uniformThemeProvider(e, props) {
                        return Vis.Theme.createUniform(props);
                    }
                    var Themes = [{
                            name: 'Uniform Color',
                            description: 'Same color everywhere.',
                            colors: uniformColors,
                            variables: uniformVariables,
                            provider: uniformThemeProvider
                        }
                    ];
                    var Transparency = { alpha: 1.0, writeDepth: false };
                    Default.Theme = Themes[0];
                    Default.MoleculeLabels = {
                        type: 'Labels',
                        params: {
                            kind: 'Residue-Full-Id',
                            labelsOptions: Vis.Labels.DefaultLabelsOptions
                        },
                        theme: {
                            template: Default.Theme,
                            colors: Default.Theme.colors,
                            variables: Default.Theme.variables,
                            transparency: Transparency, interactive: false, disableFog: false
                        }
                    };
                    Default.GenericLabels = {
                        type: 'Labels',
                        params: Vis.Labels.DefaultLabelsOptions,
                        theme: {
                            template: Default.Theme,
                            colors: Default.Theme.colors,
                            variables: Default.Theme.variables,
                            transparency: Transparency, interactive: false, disableFog: false
                        }
                    };
                })(Default = Labels.Default || (Labels.Default = {}));
            })(Labels = Visualization.Labels || (Visualization.Labels = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Density;
            (function (Density) {
                "use strict";
                var Geom = LiteMol.Core.Geometry;
                function getOffsets(data, min, max, toFrac) {
                    var dx = max[0] - min[0], dy = max[1] - min[1], dz = max[2] - min[2];
                    var corners = [
                        min,
                        [min[0] + dx, min[1], min[2]],
                        [min[0], min[1] + dy, min[2]],
                        [min[0], min[1], min[2] + dz],
                        [min[0] + dx, min[1] + dy, min[2]],
                        [min[0] + dx, min[1], min[2] + dz],
                        [min[0], min[1] + dy, min[2] + dz],
                        [min[0] + dx, min[1] + dy, min[2] + dz]
                    ].map(function (c) {
                        var f = new LiteMol.Visualization.THREE.Vector3().fromArray(c).applyMatrix4(toFrac);
                        return [f.x, f.y, f.z];
                    });
                    var bottomLeftFrac = corners[0].slice(), topRightFrac = corners[0].slice();
                    // bounding box in fractional space.
                    for (var _i = 0, corners_1 = corners; _i < corners_1.length; _i++) {
                        var c = corners_1[_i];
                        for (var i = 0; i < 3; i++) {
                            bottomLeftFrac[i] = Math.min(bottomLeftFrac[i], c[i]);
                            topRightFrac[i] = Math.max(topRightFrac[i], c[i]);
                        }
                    }
                    var _a = data.box, origin = _a.origin, dimensions = _a.dimensions, sampleCount = _a.sampleCount;
                    var bottomLeft = [0, 0, 0], topRight = [0, 0, 0];
                    // convert to the sample space.
                    for (var i = 0; i < 3; i++) {
                        var c = Math.floor(sampleCount[i] * (bottomLeftFrac[i] - origin[i]) / dimensions[i]);
                        bottomLeft[i] = Math.min(Math.max(c, 0), sampleCount[i]);
                        c = Math.ceil(sampleCount[i] * (topRightFrac[i] - origin[i]) / dimensions[i]);
                        topRight[i] = Math.min(Math.max(c, 0), sampleCount[i]);
                    }
                    return { bottomLeft: bottomLeft, topRight: topRight };
                }
                function create(parent, transform, style) {
                    var _this = this;
                    var name = style.taskType === 'Background' ? parent.props.label : "Density Surface (" + parent.props.label + ")";
                    return Bootstrap.Task.create(name, Visualization.Style.getTaskType(style), function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                        var params, source, data, basis, _a, sampleCount, origin, dimensions, scale, translate, fromFrac, toFrac, dataTransform, min, max, offsets, isSigma, isoValue, surface, theme, model, label;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0:
                                    params = style.params;
                                    source = Bootstrap.Tree.Node.findClosestNodeOfType(parent, [Bootstrap.Entity.Density.Data]);
                                    if (!source) {
                                        throw 'Cannot create density visual on ' + parent.props.label;
                                    }
                                    data = source.props.data;
                                    basis = data.spacegroup.basis;
                                    _a = data.box, sampleCount = _a.sampleCount, origin = _a.origin, dimensions = _a.dimensions;
                                    scale = new LiteMol.Visualization.THREE.Matrix4().makeScale(dimensions[0] / (sampleCount[0]), dimensions[1] / (sampleCount[1]), dimensions[2] / (sampleCount[2]));
                                    translate = new LiteMol.Visualization.THREE.Matrix4().makeTranslation(origin[0], origin[1], origin[2]);
                                    fromFrac = new LiteMol.Visualization.THREE.Matrix4().set(basis.x[0], basis.y[0], basis.z[0], 0.0, 0.0, basis.y[1], basis.z[1], 0.0, 0.0, 0.0, basis.z[2], 0.0, 0.0, 0.0, 0.0, 1.0);
                                    toFrac = new LiteMol.Visualization.THREE.Matrix4().getInverse(fromFrac);
                                    dataTransform = fromFrac.multiply(translate).multiply(scale);
                                    if (params.bottomLeft && params.topRight) {
                                        offsets = getOffsets(data, params.bottomLeft, params.topRight, toFrac);
                                        min = offsets.bottomLeft;
                                        max = offsets.topRight;
                                    }
                                    else {
                                        min = [0, 0, 0];
                                        max = data.box.sampleCount;
                                    }
                                    if (!(min[0] - max[0]) || !(min[1] - max[1]) || !(min[2] - max[2])) {
                                        throw { warn: true, message: 'Empty box.' };
                                    }
                                    isSigma = params.isoValueType === void 0 || params.isoValueType === Density.IsoValueType.Sigma;
                                    isoValue = isSigma
                                        ? data.valuesInfo.mean + data.valuesInfo.sigma * params.isoValue
                                        : params.isoValue;
                                    return [4 /*yield*/, Geom.MarchingCubes.compute({
                                            isoLevel: isoValue,
                                            scalarField: data.data,
                                            bottomLeft: min,
                                            topRight: max
                                        }).run(ctx)];
                                case 1:
                                    surface = _b.sent();
                                    return [4 /*yield*/, Geom.Surface.transform(surface, dataTransform.elements).run(ctx)];
                                case 2:
                                    surface = _b.sent();
                                    return [4 /*yield*/, Geom.Surface.laplacianSmooth(surface, params.smoothing, 8).run(ctx)];
                                case 3:
                                    surface = _b.sent();
                                    theme = style.theme.template.provider(source, Visualization.Theme.getProps(style.theme));
                                    return [4 /*yield*/, ctx.updateProgress('Creating visual...')];
                                case 4:
                                    _b.sent();
                                    return [4 /*yield*/, LiteMol.Visualization.Surface.Model.create(source, { surface: surface, theme: theme, parameters: { isWireframe: style.params.isWireframe } }).run(ctx)];
                                case 5:
                                    model = _b.sent();
                                    label = "Surface, " + Bootstrap.Utils.round(params.isoValue, 2) + (isSigma ? ' \u03C3' : '');
                                    return [2 /*return*/, Bootstrap.Entity.Density.Visual.create(transform, { label: label, model: model, style: style, isSelectable: !style.isNotSelectable })];
                            }
                        });
                    }); });
                }
                Density.create = create;
            })(Density = Visualization.Density || (Visualization.Density = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Visualization;
        (function (Visualization) {
            var Density;
            (function (Density) {
                "use strict";
                var IsoValueType;
                (function (IsoValueType) {
                    IsoValueType[IsoValueType["Sigma"] = 0] = "Sigma";
                    IsoValueType[IsoValueType["Absolute"] = 1] = "Absolute";
                })(IsoValueType = Density.IsoValueType || (Density.IsoValueType = {}));
                function areNonIsoParamsSame(a, b) {
                    return a.bottomLeft === b.bottomLeft && b.topRight === b.topRight
                        && a.smoothing === b.smoothing && a.isWireframe === b.isWireframe;
                }
                Density.areNonIsoParamsSame = areNonIsoParamsSame;
                var Style;
                (function (Style) {
                    function create(params) {
                        var colors = Default.Theme.colors.set('Uniform', params.color);
                        return {
                            type: 'Density',
                            taskType: params.taskType,
                            params: { isoValue: params.isoValue, isoValueType: params.isoValueType, smoothing: 1, isWireframe: !!params.isWireframe },
                            theme: { template: Default.Theme, colors: colors, transparency: params.transparency ? params.transparency : Default.Transparency, interactive: false, disableFog: !!params.disableFog }
                        };
                    }
                    Style.create = create;
                })(Style = Density.Style || (Density.Style = {}));
                var Default;
                (function (Default) {
                    Default.Params = {
                        isoValue: 0,
                        isoValueType: IsoValueType.Sigma,
                        smoothing: 1,
                        isWireframe: false
                    };
                    var Vis = LiteMol.Visualization;
                    var uniformBaseColor = Bootstrap.Immutable.Map({
                        'Uniform': Vis.Theme.Default.UniformColor,
                        'Highlight': Vis.Theme.Default.HighlightColor,
                        'Selection': Vis.Theme.Default.SelectionColor,
                    });
                    function uniformThemeProvider(e, props) {
                        return Vis.Theme.createUniform(props);
                    }
                    Default.Themes = [{
                            name: 'Uniform Color',
                            description: 'Same color everywhere.',
                            colors: uniformBaseColor,
                            provider: uniformThemeProvider
                        }
                    ];
                    Default.Transparency = { alpha: 1.0, writeDepth: false };
                    Default.Theme = Default.Themes[0];
                    Default.Style = { type: 'Density', params: Default.Params, theme: { template: Default.Theme, colors: Default.Theme.colors, transparency: Default.Transparency, interactive: false, disableFog: false } };
                })(Default = Density.Default || (Density.Default = {}));
            })(Density = Visualization.Density || (Visualization.Density = {}));
        })(Visualization = Bootstrap.Visualization || (Bootstrap.Visualization = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var Entity;
        (function (Entity) {
            function isClass(e, cls) {
                return e.type.info.typeClass === cls;
            }
            Entity.isClass = isClass;
            function isTypeClass(e, cls) {
                return e.info.typeClass === cls;
            }
            Entity.isTypeClass = isTypeClass;
            Entity.RootClass = 'Root';
            Entity.GroupClass = 'Group';
            Entity.DataClass = 'Data';
            Entity.ObjectClass = 'Object';
            Entity.VisualClass = 'Visual';
            Entity.SelectionClass = 'Selection';
            Entity.ActionClass = 'Action';
            Entity.BehaviourClass = 'Behaviour';
            var TypeImpl = /** @class */ (function () {
                function TypeImpl(id, infoBase, traits) {
                    this.id = id;
                    this.info = Bootstrap.Utils.assign({}, infoBase, { traits: traits });
                }
                TypeImpl.prototype.create = function (transform, props) {
                    var ret = {
                        id: Bootstrap.Tree.Node.createId(),
                        version: 0,
                        index: 0,
                        ref: 'undefined',
                        tag: void 0,
                        tree: void 0,
                        props: props,
                        state: { isCollapsed: false, visibility: 0 /* Full */ },
                        isHidden: false,
                        transform: transform,
                        parent: void 0,
                        children: [],
                        type: this
                    };
                    return Bootstrap.Tree.Node.update(ret);
                };
                return TypeImpl;
            }());
            function create(info, traits) {
                return new TypeImpl(Bootstrap.Utils.generateUUID(), info, traits ? traits : {});
            }
            Entity.create = create;
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            "use strict";
            function nodeUpdated(e) {
                if (!e.tree)
                    return;
                Bootstrap.Event.Tree.NodeUpdated.dispatch(e.tree.context, e);
                if (e.tree.context.currentEntity === e) {
                    Bootstrap.Event.Entity.CurrentChanged.dispatch(e.tree.context, e);
                }
            }
            Entity.nodeUpdated = nodeUpdated;
            function toggleExpanded(e) {
                var s = { isCollapsed: !e.state.isCollapsed };
                Bootstrap.Tree.Node.withState(e, s);
                nodeUpdated(e);
            }
            Entity.toggleExpanded = toggleExpanded;
            function setCurrent(e) {
                var old = e.tree.context.currentEntity;
                if (old === e || (e && e.isHidden)) {
                    return;
                }
                var n = e.parent;
                while (n.parent !== n) {
                    if (n.isHidden) {
                        return;
                    }
                    n = n.parent;
                }
                e.tree.context.currentEntity = e;
                if (old) {
                    Bootstrap.Tree.Node.update(old);
                    nodeUpdated(old);
                }
                if (e) {
                    Bootstrap.Tree.Node.update(e);
                    nodeUpdated(e);
                }
                Bootstrap.Event.Entity.CurrentChanged.dispatch(e.tree.context, e);
                if (old)
                    Bootstrap.Tree.updatePath(old);
                Bootstrap.Tree.updatePath(e.parent);
            }
            Entity.setCurrent = setCurrent;
            // export function forceUpdate(e: Entity.Any) {
            //     if (!e.tree) return;
            //     Event.Tree.NodeUpdated.dispatch(e.tree.context, e);
            //     if (e.tree.context.currentEntity === e) {
            //         Event.Entity.CurrentChanged.dispatch(e.tree.context, e);
            //     }
            // } 
            function updateVisibilityState(entity) {
                if (!entity)
                    return;
                var fullCount = 0;
                var noneCount = 0;
                for (var _i = 0, _a = entity.children; _i < _a.length; _i++) {
                    var n = _a[_i];
                    var s = n.state.visibility;
                    if (s === 0 /* Full */)
                        fullCount++;
                    else if (s === 2 /* None */)
                        noneCount++;
                }
                var visibility;
                if (fullCount === entity.children.length)
                    visibility = 0 /* Full */;
                else if (noneCount === entity.children.length)
                    visibility = 2 /* None */;
                else
                    visibility = 1 /* Partial */;
                if (visibility !== entity.state.visibility) {
                    var s = { visibility: visibility };
                    Bootstrap.Tree.Node.withState(entity, s);
                    nodeUpdated(entity);
                }
                if (entity.parent !== entity)
                    updateVisibilityState(entity.parent);
            }
            Entity.updateVisibilityState = updateVisibilityState;
            function setVisibility(entity, visible) {
                if (!entity)
                    return;
                var newState = visible ? 0 /* Full */ : 2 /* None */;
                Bootstrap.Tree.Node.forEach(entity, function (n) {
                    var v = n.state.visibility;
                    if (v !== newState) {
                        var s = { visibility: newState };
                        Bootstrap.Tree.Node.withState(n, s);
                        nodeUpdated(n);
                    }
                });
                updateVisibilityState(entity.parent);
            }
            Entity.setVisibility = setVisibility;
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            "use strict";
            function isMolecule(e) {
                return e && e.type === Molecule.Molecule;
            }
            Entity.isMolecule = isMolecule;
            function isMoleculeModel(e) {
                return e && e.type === Molecule.Model;
            }
            Entity.isMoleculeModel = isMoleculeModel;
            function isMoleculeSelection(e) {
                return e && e.type === Molecule.Selection;
            }
            Entity.isMoleculeSelection = isMoleculeSelection;
            function isVisual(e) {
                return e && e.type.info.typeClass === Entity.VisualClass;
            }
            Entity.isVisual = isVisual;
            /* Base */
            Entity.RootTransform = Bootstrap.Tree.Transform.create({}, {}, void 0);
            Entity.Root = Entity.create({ name: 'Root', typeClass: 'Root', shortName: 'R', description: 'Where everything begins.' });
            Entity.Group = Entity.create({ name: 'Group', typeClass: 'Group', shortName: 'G', description: 'A group on entities.' });
            Entity.Action = Entity.create({ name: 'Action', typeClass: 'Action', shortName: 'A', description: 'Represents an action performed on the entity tree.' });
            /* Data */
            var Data;
            (function (Data) {
                Data.Types = ['String', 'Binary'];
                Data.String = Entity.create({ name: 'String Data', typeClass: 'Data', shortName: 'S_D', description: 'A string.' });
                Data.Binary = Entity.create({ name: 'Binary Data', typeClass: 'Data', shortName: 'B_D', description: 'A binary blob.' });
                Data.CifDictionary = Entity.create({ name: 'Cif Dictionary', typeClass: 'Data', shortName: 'CD', description: 'Represents parsed CIF data.' });
                Data.Json = Entity.create({ name: 'JSON Data', typeClass: 'Data', shortName: 'JS_D', description: 'Represents JSON data.' });
            })(Data = Entity.Data || (Entity.Data = {}));
            // /* Visual props */
            var Visual;
            (function (Visual) {
                Visual.Surface = Entity.create({ name: 'Surface Visual', typeClass: 'Visual', shortName: 'V_S', description: 'A surface visual.' }, { isFocusable: true });
                Visual.Labels = Entity.create({ name: 'Labels Visual', typeClass: 'Visual', shortName: 'V_L', description: '3D labels.' }, { isFocusable: false });
            })(Visual = Entity.Visual || (Entity.Visual = {}));
            /* Molecule */
            var Molecule;
            (function (Molecule_1) {
                Molecule_1.Molecule = Entity.create({ name: 'Molecule', typeClass: 'Object', shortName: 'M', description: 'A molecule that might contain one or more models.' });
                Molecule_1.Model = Entity.create({ name: 'Molecule Model', typeClass: 'Object', shortName: 'M_M', description: 'A model of a molecule.' });
                Molecule_1.Selection = Entity.create({ name: 'Molecule Model Selection', typeClass: 'Selection', shortName: 'S_M', description: 'A selection of atoms.' }, { isFocusable: true });
                Molecule_1.Visual = Entity.create({ name: 'Molecule Visual', typeClass: 'Visual', shortName: 'V_M', description: 'A visual of a molecule.' }, { isFocusable: true });
                var CoordinateStreaming;
                (function (CoordinateStreaming) {
                    CoordinateStreaming.Behaviour = Entity.create({ name: 'Coordinate Streaming', typeClass: 'Behaviour', shortName: 'CS', description: 'Behaviour that downloads surrounding residues when an atom or residue is selected.' });
                })(CoordinateStreaming = Molecule_1.CoordinateStreaming || (Molecule_1.CoordinateStreaming = {}));
            })(Molecule = Entity.Molecule || (Entity.Molecule = {}));
            /* Density */
            var Density;
            (function (Density) {
                Density.Data = Entity.create({ name: 'Density Data', typeClass: 'Object', shortName: 'DD', description: 'Density data.' });
                Density.Visual = Entity.create({ name: 'Density Visual', typeClass: 'Visual', shortName: 'V_DD', description: 'A visual of density data.' }, { isFocusable: true });
                Density.InteractiveSurface = Entity.create({ name: 'Interactive Surface', typeClass: 'Behaviour', shortName: 'B_IS', description: 'Behaviour that creates an interactive surface when an atom or residue is selected.' });
            })(Density = Entity.Density || (Entity.Density = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            "use strict";
            var Cache = /** @class */ (function () {
                function Cache(context) {
                    var _this = this;
                    this.data = LiteMol.Core.Utils.FastMap.create();
                    Bootstrap.Event.Tree.NodeRemoved.getStream(context).subscribe(function (e) { return _this.data.delete(e.data.id); });
                }
                Cache.prototype.get = function (e, prop) {
                    var c = this.data.get(e.id);
                    if (c)
                        return c[prop];
                    return void 0;
                };
                Cache.prototype.set = function (e, prop, value) {
                    var _a;
                    var c = this.data.get(e.id);
                    if (c) {
                        c[prop] = value;
                    }
                    else {
                        this.data.set(e.id, (_a = {}, _a[prop] = value, _a));
                    }
                    return value;
                };
                return Cache;
            }());
            Entity.Cache = Cache;
            (function (Cache) {
                var Keys;
                (function (Keys) {
                    Keys.QueryContext = 'queryContext';
                })(Keys = Cache.Keys || (Cache.Keys = {}));
            })(Cache = Entity.Cache || (Entity.Cache = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer_1) {
                var Basic;
                (function (Basic) {
                    "use strict";
                    var _this = this;
                    var Transformer = Bootstrap.Tree.Transformer;
                    Basic.Root = Transformer.create({
                        id: 'root',
                        name: 'Root',
                        description: 'A transformer that always returns itself.',
                        from: [Entity.Root],
                        to: [Entity.Root],
                        validateParams: function () { return void 0; },
                        defaultParams: function () { return ({}); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.resolve('Root', 'Silent', a);
                    });
                    Basic.Fail = Transformer.create({
                        id: 'fail',
                        name: 'Fail',
                        description: 'A transform that always fails.',
                        from: [],
                        to: [],
                        validateParams: function () { return void 0; },
                        defaultParams: function () { return ({ title: 'Error', message: 'Unknown error.' }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.reject(t.params.title, 'Background', t.params.message);
                    });
                    Basic.CreateGroup = Transformer.create({
                        id: 'create-group',
                        name: 'Create Group',
                        description: 'A transformer that always returns itself.',
                        from: [],
                        to: [Entity.Group],
                        validateParams: function () { return void 0; },
                        defaultParams: function () { return ({}); }
                    }, function (ctx, a, t) {
                        var group = Entity.Group.create(t, { label: t.params.label ? t.params.label : 'Group', description: t.params.description });
                        if (t.params.isCollapsed) {
                            var s = { isCollapsed: true };
                            group = Bootstrap.Tree.Node.withState(group, s);
                        }
                        return Bootstrap.Task.resolve('Group', 'Silent', group);
                    });
                    Basic.Delay = Transformer.create({
                        id: 'basic-delay',
                        name: 'Delay',
                        description: 'A transformer that delays by the specified timeout and does nothing.',
                        from: [],
                        to: [Entity.Action],
                        validateParams: function () { return void 0; },
                        defaultParams: function () { return ({ timeoutMs: 1000 }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create('Delay', 'Silent', function (ctx) { return new LiteMol.Promise(function (res) {
                            setTimeout(function () { return res(Bootstrap.Tree.Node.Null); }, t.params.timeoutMs);
                        }); });
                    });
                    Basic.CreateSurfaceVisual = Bootstrap.Tree.Transformer.create({
                        id: 'basic-create-surface-visual',
                        name: 'Create Surface Visual',
                        description: 'Create generic surface visual.',
                        from: [],
                        to: [Bootstrap.Entity.Visual.Surface],
                        defaultParams: function () { return void 0; },
                        isUpdatable: false
                    }, function (context, a, t) {
                        var theme = t.params.theme;
                        var style = {
                            type: 'Surface',
                            taskType: t.params.taskType || 'Silent',
                            isNotSelectable: !!t.params.isNotInteractive,
                            params: {},
                            theme: void 0
                        };
                        return Bootstrap.Task.create("Create Surface Visual", t.params.taskType || 'Silent', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var model;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, LiteMol.Visualization.Surface.Model.create(a, { surface: t.params.surface, theme: theme, parameters: { isWireframe: t.params.isWireframe } }).run(ctx)];
                                    case 1:
                                        model = _a.sent();
                                        return [2 /*return*/, Bootstrap.Entity.Visual.Surface.create(t, {
                                                label: t.params.label || 'Surface',
                                                model: model,
                                                style: style,
                                                isSelectable: !t.params.isNotInteractive,
                                                tag: t.params.tag
                                            })];
                                }
                            });
                        }); });
                    });
                })(Basic = Transformer_1.Basic || (Transformer_1.Basic = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer) {
                var Molecule;
                (function (Molecule) {
                    "use strict";
                    var _this = this;
                    function downloadMoleculeSource(params) {
                        return Bootstrap.Tree.Transformer.action({
                            id: 'molecule-download-molecule-' + params.sourceId,
                            name: 'Molecule from ' + params.name,
                            description: params.description,
                            from: [Entity.Root],
                            to: [Entity.Action],
                            defaultParams: function (ctx) { return ({ id: params.defaultId, format: LiteMol.Core.Formats.Molecule.SupportedFormats.mmCIF }); },
                            validateParams: function (p) { return (!p.id || !p.id.trim().length) ? ["Enter " + (params.isFullUrl ? 'URL' : 'Id')] : void 0; }
                        }, function (context, a, t) {
                            var format = params.specificFormat ? params.specificFormat : t.params.format;
                            return Bootstrap.Tree.Transform.build()
                                .add(a, Transformer.Data.Download, { url: params.urlTemplate(t.params.id.trim()), type: format.isBinary ? 'Binary' : 'String', id: t.params.id, description: params.name, title: 'Molecule' })
                                .then(Molecule.CreateFromData, { format: params.specificFormat ? params.specificFormat : t.params.format }, { isBinding: true })
                                .then(Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false });
                        });
                    }
                    Molecule.downloadMoleculeSource = downloadMoleculeSource;
                    Molecule.OpenMoleculeFromFile = Bootstrap.Tree.Transformer.action({
                        id: 'molecule-open-from-file',
                        name: 'Molecule from File',
                        description: "Open a molecule from a file (" + LiteMol.Core.Formats.Molecule.SupportedFormats.All.map(function (f) { return f.name; }).join(', ') + ").",
                        from: [Entity.Root],
                        to: [Entity.Action],
                        defaultParams: function (ctx) { return ({ file: void 0 }); },
                        validateParams: function (p) { return !p.file ? ['Select a file'] : !LiteMol.Core.Formats.FormatInfo.getFormat(p.file.name, LiteMol.Core.Formats.Molecule.SupportedFormats.All)
                            ? ["Select a supported file format (" + [].concat(LiteMol.Core.Formats.Molecule.SupportedFormats.All.map(function (f) { return f.extensions; })).join(', ') + ")."]
                            : void 0; }
                    }, function (context, a, t) {
                        var format = LiteMol.Core.Formats.FormatInfo.getFormat(t.params.file.name, LiteMol.Core.Formats.Molecule.SupportedFormats.All);
                        return Bootstrap.Tree.Transform.build()
                            .add(a, Transformer.Data.OpenFile, { file: t.params.file, type: format.isBinary ? 'Binary' : 'String' })
                            .then(Molecule.CreateFromData, { format: format }, { isBinding: true })
                            .then(Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false });
                    });
                    Molecule.CreateFromData = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-from-data',
                        name: 'Molecule',
                        description: 'Create a molecule from string or binary data.',
                        from: [Entity.Data.String, Entity.Data.Binary],
                        to: [Entity.Molecule.Molecule],
                        defaultParams: function (ctx) { return ({ format: LiteMol.Core.Formats.Molecule.SupportedFormats.mmCIF }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Molecule (" + a.props.label + ")", 'Silent', function () { return __awaiter(_this, void 0, void 0, function () {
                            var r, _i, _a, w;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0: return [4 /*yield*/, Bootstrap.Task.fromComputation("Create Molecule (" + a.props.label + ")", 'Normal', t.params.format.parse(a.props.data, { id: t.params.customId }))
                                            .setReportTime(true).run(ctx)];
                                    case 1:
                                        r = _b.sent();
                                        if (r.isError)
                                            throw r.toString();
                                        if (r.warnings && r.warnings.length > 0) {
                                            for (_i = 0, _a = r.warnings; _i < _a.length; _i++) {
                                                w = _a[_i];
                                                ctx.logger.warning(w);
                                            }
                                        }
                                        return [2 /*return*/, Entity.Molecule.Molecule.create(t, { label: r.result.id, molecule: r.result })];
                                }
                            });
                        }); });
                    });
                    Molecule.CreateFromMmCif = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-from-mmcif',
                        name: 'Molecule',
                        description: 'Create a molecule from a mmCIF data block.',
                        from: [Entity.Data.CifDictionary],
                        to: [Entity.Molecule.Molecule],
                        defaultParams: function (ctx) { return ({ blockIndex: 0 }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Molecule (" + a.props.label + ")", 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var index, b, molecule;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Creating...')];
                                    case 1:
                                        _a.sent();
                                        index = t.params.blockIndex | 0;
                                        b = a.props.dictionary.dataBlocks[index];
                                        if (!b) {
                                            throw "The source contains only " + a.props.dictionary.dataBlocks.length + " data block(s), tried to access the " + (index + 1) + "-th.";
                                        }
                                        molecule = LiteMol.Core.Formats.Molecule.mmCIF.ofDataBlock(b);
                                        return [2 /*return*/, Entity.Molecule.Molecule.create(t, { label: molecule.id, molecule: molecule })];
                                }
                            });
                        }); }).setReportTime(true);
                    });
                    Molecule.CreateModel = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-model',
                        name: 'Model',
                        description: 'Create a model of a molecule.',
                        from: [Entity.Molecule.Molecule],
                        to: [Entity.Molecule.Model],
                        isUpdatable: true,
                        defaultParams: function (ctx) { return ({ modelIndex: 0 }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Model (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var params, index, model;
                            return __generator(this, function (_a) {
                                params = t.params;
                                index = params.modelIndex | 0;
                                model = a.props.molecule.models[index];
                                if (!model) {
                                    throw "The molecule contains only " + a.props.molecule.models.length + " model(s), tried to access the " + (index + 1) + "-th.";
                                }
                                return [2 /*return*/, Entity.Molecule.Model.create(t, {
                                        label: 'Model ' + model.modelId,
                                        description: model.data.atoms.count + " atom" + (model.data.atoms.count !== 1 ? 's' : ''),
                                        model: model
                                    })];
                            });
                        }); });
                    });
                    Molecule.CreateSelection = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-selection',
                        name: 'Selection',
                        description: 'Create an atom selection.',
                        from: [Entity.Molecule.Model, Entity.Molecule.Visual],
                        to: [Entity.Molecule.Selection],
                        isUpdatable: true,
                        defaultParams: function (ctx) { return ({ queryString: ctx.settings.get('molecule.model.defaultQuery') || '' }); },
                        validateParams: function (p) {
                            if (!(p.queryString || '').trim().length)
                                return ['Enter query'];
                            try {
                                return LiteMol.Core.Structure.Query.Builder.toQuery(p.queryString) && void 0 || void 0;
                            }
                            catch (e) {
                                return ['' + e];
                            }
                        },
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Selection (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var params, query, queryCtx, indices;
                            return __generator(this, function (_a) {
                                params = t.params;
                                query = LiteMol.Core.Structure.Query.Builder.toQuery(params.queryString);
                                queryCtx = t.params.inFullContext ? Bootstrap.Utils.Molecule.findModel(a).props.model.queryContext : Bootstrap.Utils.Molecule.findQueryContext(a);
                                indices = query(queryCtx).unionAtomIndices();
                                if (!indices.length) {
                                    throw { warn: true, message: "Empty selection" + (t.params.name ? ' (' + t.params.name + ')' : '') + "." };
                                }
                                return [2 /*return*/, Entity.Molecule.Selection.create(t, { label: params.name ? params.name : 'Selection', description: indices.length + " atom" + (indices.length !== 1 ? 's' : ''), indices: indices })];
                            });
                        }); }).setReportTime(!t.params.silent);
                    });
                    Molecule.CreateSelectionFromQuery = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-selection',
                        name: 'Selection',
                        description: 'Create an atom selection.',
                        from: [Entity.Molecule.Selection, Entity.Molecule.Model, Entity.Molecule.Visual],
                        to: [Entity.Molecule.Selection],
                        defaultParams: function (ctx) { return void 0; },
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Selection (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var params, query, queryCtx, indices;
                            return __generator(this, function (_a) {
                                params = t.params;
                                query = LiteMol.Core.Structure.Query.Builder.toQuery(params.query);
                                queryCtx = t.params.inFullContext ? Bootstrap.Utils.Molecule.findModel(a).props.model.queryContext : Bootstrap.Utils.Molecule.findQueryContext(a);
                                indices = query(queryCtx).unionAtomIndices();
                                if (!indices.length) {
                                    throw { warn: true, message: "Empty selection" + (t.params.name ? ' (' + t.params.name + ')' : '') + "." };
                                }
                                return [2 /*return*/, Entity.Molecule.Selection.create(t, { label: params.name ? params.name : 'Selection', description: indices.length + " atom" + (indices.length !== 1 ? 's' : ''), indices: indices })];
                            });
                        }); }).setReportTime(!t.params.silent);
                    });
                    Molecule.CreateAssembly = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-assemly',
                        name: 'Assembly',
                        description: 'Create an assembly of a molecule.',
                        from: [Entity.Molecule.Model],
                        to: [Entity.Molecule.Model],
                        defaultParams: function (ctx, e) {
                            var m = Bootstrap.Utils.Molecule.findModel(e);
                            var ret = ({ name: ctx.settings.get('molecule.model.defaultAssemblyName') || '1' });
                            var asm = m.props.model.data.assemblyInfo;
                            if (!asm || !asm.assemblies.length)
                                return ret;
                            if (asm.assemblies.filter(function (a) { return a.name === ret.name; }))
                                return ret;
                            ret.name = asm.assemblies[0].name;
                            return ret;
                        },
                        isUpdatable: true,
                        isApplicable: function (m) { return !!(m && m.props.model.data.assemblyInfo && m.props.model.data.assemblyInfo.assemblies.length); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Model (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var i, gen, asm;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        i = a.props.model.data.assemblyInfo;
                                        if (!i || !i.assemblies.length) {
                                            throw 'Assembly info not available.';
                                        }
                                        gen = i.assemblies.filter(function (a) { return a.name === t.params.name; })[0];
                                        if (!gen) {
                                            throw "No assembly called '" + t.params.name + "' found.";
                                        }
                                        return [4 /*yield*/, ctx.updateProgress('Creating...')];
                                    case 1:
                                        _a.sent();
                                        asm = LiteMol.Core.Structure.buildAssembly(a.props.model, gen);
                                        return [2 /*return*/, Entity.Molecule.Model.create(t, {
                                                label: 'Assembly ' + gen.name,
                                                description: asm.data.atoms.count + " atom" + (asm.data.atoms.count !== 1 ? 's' : ''),
                                                model: asm
                                            })];
                                }
                            });
                        }); });
                    });
                    Molecule.CreateSymmetryMates = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-symmetry-mates',
                        name: 'Crystal Symmetry',
                        description: 'Find crystal symmetry mates or interaction partners.',
                        from: [Entity.Molecule.Model],
                        to: [Entity.Molecule.Model],
                        defaultParams: function (ctx) { return ({ type: 'Interaction', radius: 5.0 }); },
                        isUpdatable: true,
                        isApplicable: function (m) {
                            if (!m || !m.props.model.data.symmetryInfo)
                                return false;
                            var info = m.props.model.data.symmetryInfo;
                            if (info.cellSize[0] === 1 && info.cellSize[1] === 1 && info.cellSize[2] === 1)
                                return false;
                            return true;
                        }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Create Model (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var i, radius, symm;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        i = a.props.model.data.symmetryInfo;
                                        if (!i) {
                                            throw 'Spacegroup info info not available.';
                                        }
                                        radius = Math.max(t.params.radius, 0);
                                        return [4 /*yield*/, ctx.updateProgress('Creating...')];
                                    case 1:
                                        _a.sent();
                                        symm = t.params.type === 'Mates' ? LiteMol.Core.Structure.buildSymmetryMates(a.props.model, radius) : LiteMol.Core.Structure.buildPivotGroupSymmetry(a.props.model, radius);
                                        return [2 /*return*/, Entity.Molecule.Model.create(t, {
                                                label: 'Symmetry',
                                                model: symm,
                                                description: symm.data.atoms.count + " atom" + (symm.data.atoms.count !== 1 ? 's' : '') + ", " + t.params.type + " " + Bootstrap.Utils.round(radius, 1) + " \u212B"
                                            })];
                                }
                            });
                        }); });
                    });
                    Molecule.ModelTransform3D = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-model-transform3d',
                        name: 'Transform 3D',
                        description: 'Transform 3D coordinates of a model using a 4x4 matrix.',
                        from: [Entity.Molecule.Model],
                        to: [Entity.Molecule.Model],
                        validateParams: function (p) { return !p || !p.transform || p.transform.length !== 16 ? ['Specify a 4x4 transform matrix.'] : void 0; },
                        defaultParams: function (ctx, e) { return ({ transform: LiteMol.Core.Geometry.LinearAlgebra.Matrix4.identity() }); },
                        isUpdatable: false
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create("Transform 3D (" + a.props.label + ")", 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var m, tCtx, transformed;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Transforming...')];
                                    case 1:
                                        _a.sent();
                                        m = a.props.model;
                                        tCtx = { t: t.params.transform, v: LiteMol.Core.Geometry.LinearAlgebra.Vector3.zero() };
                                        transformed = LiteMol.Core.Structure.Molecule.Model.withTransformedXYZ(m, tCtx, function (ctx, x, y, z, out) {
                                            var v = ctx.v;
                                            LiteMol.Core.Geometry.LinearAlgebra.Vector3.set(v, x, y, z);
                                            LiteMol.Core.Geometry.LinearAlgebra.Vector3.transformMat4(out, v, ctx.t);
                                        });
                                        return [2 /*return*/, Entity.Molecule.Model.create(t, {
                                                label: a.props.label,
                                                description: t.params.description ? t.params.description : 'Transformed',
                                                model: transformed
                                            })];
                                }
                            });
                        }); });
                    });
                    Molecule.CreateVisual = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-visual',
                        name: 'Visual',
                        description: 'Create a visual of a molecule or a selection.',
                        from: [Entity.Molecule.Model, Entity.Molecule.Selection],
                        to: [Entity.Molecule.Visual],
                        isUpdatable: true,
                        defaultParams: function (ctx) { return ({ style: Bootstrap.Visualization.Molecule.Default.ForType.get('Cartoons') }); },
                        validateParams: function (p) { return !p.style ? ['Specify Style'] : void 0; },
                        customController: function (ctx, t, e) { return new Bootstrap.Components.Transform.MoleculeVisual(ctx, t, e); }
                    }, function (ctx, a, t) {
                        var params = t.params;
                        return Bootstrap.Visualization.Molecule.create(a, t, params.style).setReportTime(Bootstrap.Visualization.Style.getTaskType(t.params.style) === 'Normal');
                    }, function (ctx, b, t) {
                        var oldParams = b.transform.params;
                        if (oldParams.style.type !== t.params.style.type || !Bootstrap.Utils.deepEqual(oldParams.style.params, t.params.style.params))
                            return void 0;
                        var model = b.props.model;
                        if (!model)
                            return void 0;
                        var a = Bootstrap.Utils.Molecule.findModel(b.parent);
                        if (!a)
                            return void 0;
                        var ti = t.params.style.theme;
                        var theme = ti.template.provider(a, Bootstrap.Visualization.Theme.getProps(ti));
                        model.applyTheme(theme);
                        b.props.style = t.params.style;
                        Entity.nodeUpdated(b);
                        return Bootstrap.Task.resolve(t.transformer.info.name, 'Background', Bootstrap.Tree.Node.Null);
                    });
                    Molecule.CreateMacromoleculeVisual = Bootstrap.Tree.Transformer.action({
                        id: 'molecule-create-macromolecule-visual',
                        name: 'Macromolecule Visual',
                        description: 'Create a visual of a molecule that is split into polymer, HET, and water parts.',
                        from: [Entity.Molecule.Selection, Entity.Molecule.Model],
                        to: [Entity.Action],
                        validateParams: function (p) { return !p.polymer && !p.het && !p.water ? ['Select at least one component'] : void 0; },
                        defaultParams: function (ctx) { return ({ polymer: true, het: true, water: true }); },
                    }, function (context, a, t) {
                        var g = Bootstrap.Tree.Transform.build().add(a, Transformer.Basic.CreateGroup, { label: 'Group', description: 'Macromolecule' }, { ref: t.params.groupRef });
                        if (t.params.polymer) {
                            g.then(Molecule.CreateSelectionFromQuery, { query: LiteMol.Core.Structure.Query.nonHetPolymer(), name: 'Polymer', silent: true }, { isBinding: true })
                                .then(Molecule.CreateVisual, { style: Bootstrap.Visualization.Molecule.Default.ForType.get('Cartoons') }, { ref: t.params.polymerRef });
                        }
                        if (t.params.het) {
                            g.then(Molecule.CreateSelectionFromQuery, { query: LiteMol.Core.Structure.Query.hetGroups(), name: 'HET', silent: true }, { isBinding: true })
                                .then(Molecule.CreateVisual, { style: Bootstrap.Visualization.Molecule.Default.ForType.get('BallsAndSticks') }, { ref: t.params.hetRef });
                        }
                        if (t.params.water) {
                            var style = {
                                type: 'BallsAndSticks',
                                params: { useVDW: false, atomRadius: 0.23, bondRadius: 0.09, detail: 'Automatic' },
                                theme: { template: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate, colors: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate.colors, transparency: { alpha: 0.25 } }
                            };
                            g.then(Molecule.CreateSelectionFromQuery, { query: LiteMol.Core.Structure.Query.entities({ type: 'water' }), name: 'Water', silent: true }, { isBinding: true })
                                .then(Molecule.CreateVisual, { style: style }, { ref: t.params.waterRef });
                        }
                        return g;
                    });
                    Molecule.CreateLabels = Bootstrap.Tree.Transformer.create({
                        id: 'molecule-create-labels',
                        name: 'Labels',
                        description: 'Create a labels for a molecule or a selection.',
                        from: [Entity.Molecule.Model, Entity.Molecule.Selection, Entity.Molecule.Visual],
                        to: [Entity.Visual.Labels],
                        isUpdatable: true,
                        defaultParams: function (ctx) { return ({ style: Bootstrap.Visualization.Labels.Default.MoleculeLabels }); },
                        validateParams: function (p) { return !p.style ? ['Specify Style'] : void 0; },
                        customController: function (ctx, t, e) { return new Bootstrap.Components.Transform.MoleculeLabels(ctx, t, e); }
                    }, function (ctx, a, t) {
                        var params = t.params;
                        return Bootstrap.Visualization.Labels.createMoleculeLabels(a, t, params.style).setReportTime(false);
                    }, function (ctx, b, t) {
                        var oldParams = b.transform.params;
                        var newParams = t.params;
                        if (!Bootstrap.Visualization.Labels.Style.moleculeHasOnlyThemeChanged(oldParams.style, newParams.style))
                            return void 0;
                        var model = b.props.model;
                        var a = Bootstrap.Tree.Node.findClosestNodeOfType(b, [Entity.Molecule.Model, Entity.Molecule.Selection, Entity.Molecule.Visual]);
                        if (!a)
                            return void 0;
                        var theme = newParams.style.theme.template.provider(a, Bootstrap.Visualization.Theme.getProps(newParams.style.theme));
                        model.applyTheme(theme);
                        Entity.nodeUpdated(b);
                        return Bootstrap.Task.resolve(t.transformer.info.name, 'Background', Bootstrap.Tree.Node.Null);
                    });
                })(Molecule = Transformer.Molecule || (Transformer.Molecule = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer) {
                var Labels;
                (function (Labels) {
                    Labels.Create = Bootstrap.Tree.Transformer.create({
                        id: 'labels-create',
                        name: 'Labels',
                        description: 'Create a labels for a molecule or a selection.',
                        from: [],
                        to: [Entity.Visual.Labels],
                        isUpdatable: false,
                        defaultParams: function (ctx) { return ({}); },
                        customController: function (ctx, t, e) { return new Bootstrap.Components.Transform.MoleculeLabels(ctx, t, e); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Visualization.Labels.createGenericLabels(a, t, t.params).setReportTime(false);
                    }, function (ctx, b, t) {
                        var oldParams = b.transform.params;
                        var newParams = t.params;
                        if (oldParams.positions !== newParams.positions
                            || oldParams.sizes !== newParams.sizes
                            || oldParams.labels !== newParams.labels
                            || oldParams.options !== newParams.options) {
                            return void 0;
                        }
                        var model = b.props.model;
                        var a = Bootstrap.Tree.Node.findClosestNodeOfType(b, [Entity.Root]);
                        if (!a)
                            return void 0;
                        var theme = newParams.style.theme.template.provider(a, Bootstrap.Visualization.Theme.getProps(newParams.style.theme));
                        model.applyTheme(theme);
                        Entity.nodeUpdated(b);
                        return Bootstrap.Task.resolve(t.transformer.info.name, 'Background', Bootstrap.Tree.Node.Null);
                    });
                })(Labels = Transformer.Labels || (Transformer.Labels = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer) {
                var Data;
                (function (Data) {
                    "use strict";
                    var _this = this;
                    function getDataType(type) {
                        if (type === void 0 || type === null)
                            return 'String';
                        if (type.toLowerCase() === 'binary')
                            return 'Binary';
                        return 'String';
                    }
                    function hasResponseCompression(responseCompression) {
                        var c = responseCompression === void 0 ? Bootstrap.Utils.DataCompressionMethod.None : responseCompression;
                        return c !== Bootstrap.Utils.DataCompressionMethod.None;
                    }
                    Data.Download = Bootstrap.Tree.Transformer.create({
                        id: 'data-download',
                        name: 'Download Data',
                        description: 'Downloads a string or binary data from the given URL (if the host server supports cross domain requests).',
                        from: [Entity.Root],
                        to: [Entity.Data.String, Entity.Data.Binary],
                        validateParams: function (p) { return !p.url || !p.url.trim().length ? ['Enter URL'] : !p.type ? ['Specify type'] : (p.type === 'String' && hasResponseCompression(p.responseCompression)) ? ['Decompression is only available for Binary data.'] : void 0; },
                        defaultParams: function () { return ({ id: '', description: '', type: 'String', url: '', responseCompression: Bootstrap.Utils.DataCompressionMethod.None }); }
                    }, function (ctx, a, t) {
                        var params = t.params;
                        return Bootstrap.Task.create('Download', 'Silent', function () { return __awaiter(_this, void 0, void 0, function () {
                            var data;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, Bootstrap.Utils.ajaxGet({ url: params.url, type: getDataType(params.type), compression: params.responseCompression, title: params.title }).setReportTime(true).run(ctx)];
                                    case 1:
                                        data = _a.sent();
                                        if (params.type === 'String')
                                            return [2 /*return*/, Entity.Data.String.create(t, { label: params.id ? params.id : params.url, description: params.description, data: data })];
                                        else
                                            return [2 /*return*/, Entity.Data.Binary.create(t, { label: params.id ? params.id : params.url, description: params.description, data: data })];
                                        return [2 /*return*/];
                                }
                            });
                        }); });
                    });
                    Data.OpenFile = Bootstrap.Tree.Transformer.create({
                        id: 'data-open-file',
                        name: 'Open Data File',
                        description: 'Read a string or binary data from the selected file.',
                        from: [Entity.Root],
                        to: [Entity.Data.String, Entity.Data.Binary],
                        validateParams: function (p) { return !p.file ? ['Select a file'] : void 0; },
                        defaultParams: function () { return ({ type: 'String', file: void 0 }); }
                    }, function (ctx, a, t) {
                        return Bootstrap.Task.create('Download', 'Silent', function (taskCtx) { return __awaiter(_this, void 0, void 0, function () {
                            var params, data;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        params = t.params;
                                        return [4 /*yield*/, Bootstrap.Utils.readFromFile(params.file, getDataType(params.type)).setReportTime(true).run(ctx)];
                                    case 1:
                                        data = _a.sent();
                                        if (params.type === 'String')
                                            return [2 /*return*/, Entity.Data.String.create(t, { label: params.id ? params.id : params.file.name, description: params.description, data: data })];
                                        else
                                            return [2 /*return*/, Entity.Data.Binary.create(t, { label: params.id ? params.id : params.file.name, description: params.description, data: data })];
                                        return [2 /*return*/];
                                }
                            });
                        }); });
                    });
                    Data.ParseCif = Bootstrap.Tree.Transformer.create({
                        id: 'data-parse-cif',
                        name: 'CIF Dictionary',
                        description: 'Parse CIF dictionary from a string.',
                        from: [Entity.Data.String],
                        to: [Entity.Data.CifDictionary],
                        defaultParams: function () { return ({}); }
                    }, function (bigCtx, a, t) {
                        return Bootstrap.Task.create("CIF Parse (" + a.props.label + ")", 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var d;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                    case 1:
                                        _a.sent();
                                        d = LiteMol.Core.Formats.CIF.Text.parse(a.props.data);
                                        if (d.isError) {
                                            throw d.toString();
                                        }
                                        return [2 /*return*/, Entity.Data.CifDictionary.create(t, { label: t.params.id ? t.params.id : 'CIF Dictionary', description: t.params.description, dictionary: d.result })];
                                }
                            });
                        }); }).setReportTime(true);
                    });
                    Data.ParseBinaryCif = Bootstrap.Tree.Transformer.create({
                        id: 'data-parse-binary-cif',
                        name: 'CIF Dictionary',
                        description: 'Parse CIF dictionary from BinaryCIF data.',
                        from: [Entity.Data.Binary],
                        to: [Entity.Data.CifDictionary],
                        defaultParams: function () { return ({}); }
                    }, function (bigCtx, a, t) {
                        return Bootstrap.Task.create("BinaryCIF Parse (" + a.props.label + ")", 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var d;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                    case 1:
                                        _a.sent();
                                        d = LiteMol.Core.Formats.CIF.Binary.parse(a.props.data);
                                        if (d.isError) {
                                            throw d.toString();
                                        }
                                        return [2 /*return*/, Entity.Data.CifDictionary.create(t, { label: t.params.id ? t.params.id : 'CIF Dictionary', description: t.params.description, dictionary: d.result })];
                                }
                            });
                        }); }).setReportTime(true);
                    });
                    Data.ParseJson = Bootstrap.Tree.Transformer.create({
                        id: 'data-parse-json',
                        name: 'JSON',
                        description: 'Parse a string to JSON object.',
                        from: [Entity.Data.String],
                        to: [Entity.Data.Json],
                        defaultParams: function () { return ({}); }
                    }, function (bigCtx, a, t) {
                        return Bootstrap.Task.create("JSON Parse (" + a.props.label + ")", 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var data;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                    case 1:
                                        _a.sent();
                                        data = JSON.parse(a.props.data);
                                        return [2 /*return*/, Entity.Data.Json.create(t, { label: t.params.id ? t.params.id : 'JSON Data', description: t.params.description, data: data })];
                                }
                            });
                        }); }).setReportTime(true);
                    });
                    Data.FromData = Bootstrap.Tree.Transformer.create({
                        id: 'data-from-data',
                        name: 'From Data',
                        description: 'Creates a data entity from string or binary data',
                        from: [Entity.Root],
                        to: [Entity.Data.String, Entity.Data.Binary],
                        defaultParams: function () { return void 0; }
                    }, function (ctx, a, t) {
                        var data = t.params.data;
                        var e = data instanceof ArrayBuffer
                            ? Entity.Data.Binary.create(t, { label: t.params.id ? t.params.id : "Binary Data", description: t.params.description, data: data })
                            : Entity.Data.String.create(t, { label: t.params.id ? t.params.id : "String Data", description: t.params.description, data: data });
                        return Bootstrap.Task.resolve("From Data", 'Silent', e);
                    });
                })(Data = Transformer.Data || (Transformer.Data = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer) {
                var Density;
                (function (Density) {
                    "use strict";
                    var _this = this;
                    Density.ParseData = Bootstrap.Tree.Transformer.create({
                        id: 'density-parse-binary',
                        name: 'Density Data',
                        description: 'Parse density from binary data.',
                        from: [Entity.Data.String, Entity.Data.Binary],
                        to: [Entity.Density.Data],
                        isUpdatable: true,
                        defaultParams: function () { return ({ format: LiteMol.Core.Formats.Density.SupportedFormats.CCP4 }); }
                    }, function (bigCtx, a, t) {
                        return Bootstrap.Task.create("Create Density (" + a.props.label + ")", 'Background', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var data, e;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, Bootstrap.Task.fromComputation("Parse Density (" + a.props.label + ")", 'Normal', t.params.format.parse(a.props.data)).setReportTime(true).run(bigCtx)];
                                    case 1:
                                        data = _a.sent();
                                        if (data.isError) {
                                            throw data.toString();
                                        }
                                        e = Entity.Density.Data.create(t, { label: t.params.id ? t.params.id : 'Density Data', data: data.result });
                                        return [2 /*return*/, e];
                                }
                            });
                        }); });
                    });
                    Density.CreateFromCif = Bootstrap.Tree.Transformer.create({
                        id: 'density-create-from-cif',
                        name: 'Density Data',
                        description: 'Parse density from CIF data.',
                        from: [Entity.Data.CifDictionary],
                        to: [Entity.Density.Data],
                        isUpdatable: false,
                        defaultParams: function () { return ({ blockIndex: 0 }); }
                    }, function (bigCtx, a, t) {
                        return Bootstrap.Task.create('Create Density', 'Normal', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                            var data;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, ctx.updateProgress('Parsing...')];
                                    case 1:
                                        _a.sent();
                                        data = LiteMol.Core.Formats.Density.CIF.parse(a.props.dictionary.dataBlocks[t.params.blockIndex]);
                                        if (data.isError) {
                                            throw data.toString();
                                        }
                                        return [2 /*return*/, Entity.Density.Data.create(t, { label: t.params.id ? t.params.id : 'Density Data', data: data.result, description: data.result.name })];
                                }
                            });
                        }); }).setReportTime(true);
                    });
                    Density.CreateFromData = Bootstrap.Tree.Transformer.create({
                        id: 'density-create-from-data',
                        name: 'Density Data',
                        description: 'Create density from data.',
                        from: [],
                        to: [Entity.Density.Data],
                        isUpdatable: false,
                        defaultParams: function () { return ({}); }
                    }, function (ctx, a, t) {
                        var e = Entity.Density.Data.create(t, { label: t.params.id ? t.params.id : 'Density Data', data: t.params.data, description: t.params.data.name });
                        return Bootstrap.Task.resolve('Create Density', 'Background', e);
                    });
                    Density.CreateVisual = Bootstrap.Tree.Transformer.create({
                        id: 'density-create-visual',
                        name: 'Surface',
                        description: 'Create a surface from the density data.',
                        from: [Entity.Density.Data],
                        to: [Entity.Density.Visual],
                        isUpdatable: true,
                        defaultParams: function () { return ({ style: Bootstrap.Visualization.Density.Default.Style }); },
                        validateParams: function (p) { return !p.style ? ['Specify Style'] : void 0; },
                        customController: function (ctx, t, e) { return new Bootstrap.Components.Transform.DensityVisual(ctx, t, e); },
                    }, function (ctx, a, t) {
                        var params = t.params;
                        return Bootstrap.Visualization.Density.create(a, t, params.style).setReportTime(Bootstrap.Visualization.Style.getTaskType(t.params.style) === 'Normal');
                    }, function (ctx, b, t) {
                        var oldStyle = b.transform.params.style;
                        var newStyle = t.params.style;
                        if (oldStyle.type !== t.params.style.type)
                            return void 0;
                        var parent = Bootstrap.Tree.Node.findClosestNodeOfType(b, [Entity.Density.Data]);
                        if (!parent)
                            return void 0;
                        var model = b.props.model;
                        if (!model)
                            return void 0;
                        if (!compareVisualParams(parent.props.data, oldStyle.params, newStyle.params))
                            return void 0;
                        if (!Bootstrap.Utils.deepEqual(oldStyle.theme, t.params.style.theme)) {
                            var ti = newStyle.theme;
                            var theme = ti.template.provider(parent, Bootstrap.Visualization.Theme.getProps(ti));
                            model.applyTheme(theme);
                            b.props.style.theme = ti;
                            Entity.nodeUpdated(b);
                        }
                        return Bootstrap.Task.resolve(t.transformer.info.name, 'Background', Bootstrap.Tree.Node.Null);
                    });
                    Density.CreateVisualBehaviour = Bootstrap.Tree.Transformer.create({
                        id: 'density-create-visual-behaviour',
                        name: 'Interactive Surface',
                        description: 'Create a surface from the density data when a residue or atom is selected.',
                        from: [Entity.Density.Data],
                        to: [Entity.Density.InteractiveSurface],
                        isUpdatable: true,
                        defaultParams: function (ctx) { return ({ style: Bootstrap.Visualization.Density.Default.Style, radius: ctx.settings.get('density.defaultVisualBehaviourRadius') || 0, isoSigmaMin: -5, isoSigmaMax: 5, minRadius: 0, maxRadius: 10, showFull: false }); },
                        customController: function (ctx, t, e) { return new Bootstrap.Components.Transform.DensityVisual(ctx, t, e); },
                    }, function (ctx, a, t) {
                        var params = t.params;
                        var b = new Bootstrap.Behaviour.Density.ShowDynamicDensity(ctx, {
                            style: params.style,
                            radius: params.radius,
                            showFull: params.showFull
                        });
                        var isSigma = params.style.params.isoValueType === void 0 || params.style.params.isoValueType === Bootstrap.Visualization.Density.IsoValueType.Sigma;
                        return Bootstrap.Task.resolve('Behaviour', 'Background', Entity.Density.InteractiveSurface.create(t, { label: (params.id ? t.params.id : 'Interactive') + ", " + Bootstrap.Utils.round(params.style.params.isoValue, 2) + (isSigma ? ' \u03C3' : ''), behaviour: b }));
                    }, function (ctx, b, t) {
                        var oldParams = b.transform.params;
                        var newParams = t.params;
                        if (oldParams.style.type !== newParams.style.type)
                            return void 0;
                        if (oldParams.isoSigmaMin !== newParams.isoSigmaMin
                            || oldParams.isoSigmaMax !== newParams.isoSigmaMax
                            || oldParams.minRadius !== newParams.minRadius
                            || oldParams.maxRadius !== newParams.maxRadius
                            || oldParams.radius !== newParams.radius
                            || oldParams.showFull !== newParams.showFull) {
                            return void 0;
                        }
                        var parent = Bootstrap.Tree.Node.findClosestNodeOfType(b, [Entity.Density.Data]);
                        if (!parent)
                            return void 0;
                        if (!compareVisualParams(parent.props.data, oldParams.style.params, newParams.style.params))
                            return void 0;
                        var ti = newParams.style.theme;
                        b.props.behaviour.updateTheme(ti);
                        Entity.nodeUpdated(b);
                        return Bootstrap.Task.resolve(t.transformer.info.name, 'Background', Bootstrap.Tree.Node.Null);
                    });
                    function compareVisualParams(data, a, b) {
                        if (!Bootstrap.Visualization.Density.areNonIsoParamsSame(a, b))
                            return false;
                        var valuesInfo = data.valuesInfo;
                        var oldIso = a.isoValueType === Bootstrap.Visualization.Density.IsoValueType.Absolute
                            ? a.isoValue : valuesInfo.mean + valuesInfo.sigma * a.isoValue;
                        var newIso = b.isoValueType === Bootstrap.Visualization.Density.IsoValueType.Absolute
                            ? b.isoValue : valuesInfo.mean + valuesInfo.sigma * b.isoValue;
                        return Math.abs(oldIso - newIso) < 1e-6;
                    }
                })(Density = Transformer.Density || (Transformer.Density = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Entity;
        (function (Entity) {
            var Transformer;
            (function (Transformer) {
                var Molecule;
                (function (Molecule) {
                    var CoordinateStreaming;
                    (function (CoordinateStreaming) {
                        "use strict";
                        var _this = this;
                        CoordinateStreaming.CreateBehaviour = Bootstrap.Tree.Transformer.create({
                            id: 'streaming-create-behaviour',
                            name: 'Coordinate Streaming',
                            description: 'Enable coordinate data streaming for this molecule.',
                            from: [Entity.Molecule.Model],
                            to: [Entity.Molecule.CoordinateStreaming.Behaviour],
                            defaultParams: function (ctx) { return ({ server: ctx.settings.get('molecule.coordinateStreaming.defaultServer') || '', radius: ctx.settings.get('molecule.coordinateStreaming.defaultRadius') || 0 }); },
                        }, function (ctx, a, t) {
                            return Bootstrap.Task.resolve('Behaviour', 'Background', Entity.Molecule.CoordinateStreaming.Behaviour.create(t, { label: "Coordinate Streaming", behaviour: new Bootstrap.Behaviour.Molecule.CoordinateStreaming(ctx, t.params.server, t.params.radius) }));
                        });
                        CoordinateStreaming.CreateModel = Bootstrap.Tree.Transformer.create({
                            id: 'streaming-create-model',
                            name: 'Streaming Model',
                            description: '',
                            from: [Entity.Molecule.CoordinateStreaming.Behaviour],
                            to: [Entity.Molecule.Model],
                            defaultParams: function () { return void 0; },
                        }, function (ctx, a, t) {
                            return Bootstrap.Task.create('Load', 'Silent', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
                                var cif, model;
                                return __generator(this, function (_a) {
                                    cif = LiteMol.Core.Formats.CIF.Binary.parse(t.params.data);
                                    if (cif.isError)
                                        throw new Error('Invalid CIF.');
                                    model = LiteMol.Core.Formats.Molecule.mmCIF.ofDataBlock(cif.result.dataBlocks[0]).models[0];
                                    if (t.params.transform)
                                        LiteMol.Core.Structure.Operator.applyToModelUnsafe(t.params.transform, model);
                                    return [2 /*return*/, Entity.Molecule.Model.create(t, { label: 'part', model: model })];
                                });
                            }); });
                        });
                        CoordinateStreaming.InitStreaming = Bootstrap.Tree.Transformer.action({
                            id: 'streaming-init',
                            name: 'Coordinate Streaming',
                            description: 'Download a smaller version of the molecule required to display cartoon representation and stream the rest of the coordinates as required.',
                            from: [Entity.Root],
                            to: [Entity.Action],
                            validateParams: function (p) { return !(p.id || '').trim().length ? ['Enter id'] : !(p.server || '').trim().length ? ['Specify server'] : void 0; },
                            defaultParams: function (ctx) { return ({ id: ctx.settings.get('molecule.coordinateStreaming.defaultId') || '', server: ctx.settings.get('molecule.coordinateStreaming.defaultServer') || '', radius: ctx.settings.get('molecule.coordinateStreaming.defaultRadius') || 0 }); },
                        }, function (context, a, t) {
                            return Bootstrap.Tree.Transform.build()
                                .add(a, Transformer.Data.Download, { url: Bootstrap.Behaviour.Molecule.CoordinateStreaming.getBaseUrl(t.params.id, t.params.server), type: 'Binary', id: t.params.id })
                                .then(Transformer.Data.ParseBinaryCif, { id: t.params.id }, { isBinding: true })
                                .then(Molecule.CreateFromMmCif, { blockIndex: 0 }, { isBinding: true })
                                .then(Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false })
                                .then(CoordinateStreaming.CreateBehaviour, { server: t.params.server, radius: t.params.radius });
                        });
                    })(CoordinateStreaming = Molecule.CoordinateStreaming || (Molecule.CoordinateStreaming = {}));
                })(Molecule = Transformer.Molecule || (Transformer.Molecule = {}));
            })(Transformer = Entity.Transformer || (Entity.Transformer = {}));
        })(Entity = Bootstrap.Entity || (Bootstrap.Entity = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Utils;
        (function (Utils) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                var Geometry = LiteMol.Core.Geometry;
                var LA = Geometry.LinearAlgebra;
                var __model = [Bootstrap.Entity.Molecule.Model];
                function findModel(entity) {
                    return Bootstrap.Tree.Node.findClosestNodeOfType(entity, __model);
                }
                Molecule.findModel = findModel;
                var __modelOrSelection = [Bootstrap.Entity.Molecule.Model, Bootstrap.Entity.Molecule.Selection];
                function findModelOrSelection(entity) {
                    return Bootstrap.Tree.Node.findClosestNodeOfType(entity, __modelOrSelection);
                }
                Molecule.findModelOrSelection = findModelOrSelection;
                var __molecule = [Bootstrap.Entity.Molecule.Molecule];
                function findMolecule(entity) {
                    return Bootstrap.Tree.Node.findClosestNodeOfType(entity, __molecule);
                }
                Molecule.findMolecule = findMolecule;
                function findQueryContext(entity) {
                    var source = Bootstrap.Tree.Node.findClosestNodeOfType(entity, __modelOrSelection);
                    if (Bootstrap.Entity.isMoleculeModel(source)) {
                        return source.props.model.queryContext;
                    }
                    else {
                        var cache = source.tree.context.entityCache;
                        var ctx = cache.get(source, Bootstrap.Entity.Cache.Keys.QueryContext);
                        if (ctx)
                            return ctx;
                        ctx = LiteMol.Core.Structure.Query.Context.ofAtomIndices(findModel(source).props.model, source.props.indices);
                        return cache.set(source, Bootstrap.Entity.Cache.Keys.QueryContext, ctx);
                    }
                }
                Molecule.findQueryContext = findQueryContext;
                function getDistance(mA, startAtomIndexA, endAtomIndexA, mB, startAtomIndexB, endAtomIndexB) {
                    var _a = mA.positions, x = _a.x, y = _a.y, z = _a.z;
                    var _c = mB.positions, bX = _c.x, bY = _c.y, bZ = _c.z;
                    var d = Number.POSITIVE_INFINITY;
                    for (var i = startAtomIndexA; i < endAtomIndexA; i++) {
                        for (var j = startAtomIndexB; j < endAtomIndexB; j++) {
                            var dx = x[i] - bX[j], dy = y[i] - bY[j], dz = z[i] - bZ[j];
                            d = Math.min(d, dx * dx + dy * dy + dz * dz);
                        }
                    }
                    return Math.sqrt(d);
                }
                Molecule.getDistance = getDistance;
                function getDistanceSet(mA, setA, mB, setB) {
                    var _a = mA.positions, x = _a.x, y = _a.y, z = _a.z;
                    var _c = mB.positions, bX = _c.x, bY = _c.y, bZ = _c.z;
                    var d = Number.POSITIVE_INFINITY;
                    for (var _i = 0, setA_1 = setA; _i < setA_1.length; _i++) {
                        var i = setA_1[_i];
                        for (var _d = 0, setB_1 = setB; _d < setB_1.length; _d++) {
                            var j = setB_1[_d];
                            var dx = x[i] - bX[j], dy = y[i] - bY[j], dz = z[i] - bZ[j];
                            d = Math.min(d, dx * dx + dy * dy + dz * dz);
                        }
                    }
                    return Math.sqrt(d);
                }
                Molecule.getDistanceSet = getDistanceSet;
                function getModelAndIndicesFromQuery(m, query) {
                    var model = findModel(m);
                    if (!model) {
                        console.warn('Could not find a model for query selection.');
                        return void 0;
                    }
                    var queryContext = findQueryContext(m);
                    try {
                        var q = LiteMol.Core.Structure.Query.Builder.toQuery(query);
                        return { model: model, indices: q(queryContext).unionAtomIndices(), queryContext: queryContext };
                    }
                    catch (e) {
                        console.error('Query Execution', e);
                        return void 0;
                    }
                }
                Molecule.getModelAndIndicesFromQuery = getModelAndIndicesFromQuery;
                function getResidueIndices(m, atom) {
                    var rI = m.data.atoms.residueIndex;
                    var idx = [];
                    for (var i = m.data.residues.atomStartIndex[rI[atom]], _b = m.data.residues.atomEndIndex[rI[atom]]; i < _b; i++) {
                        idx.push(i);
                    }
                    return idx;
                }
                Molecule.getResidueIndices = getResidueIndices;
                function getBox(molecule, atomIndices, delta) {
                    var _a = molecule.positions, x = _a.x, y = _a.y, z = _a.z, min = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE], max = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
                    for (var _i = 0, atomIndices_3 = atomIndices; _i < atomIndices_3.length; _i++) {
                        var i = atomIndices_3[_i];
                        min[0] = Math.min(x[i], min[0]);
                        min[1] = Math.min(y[i], min[1]);
                        min[2] = Math.min(z[i], min[2]);
                        max[0] = Math.max(x[i], max[0]);
                        max[1] = Math.max(y[i], max[1]);
                        max[2] = Math.max(z[i], max[2]);
                    }
                    min[0] = min[0] - delta;
                    min[1] = min[1] - delta;
                    min[2] = min[2] - delta;
                    max[0] = max[0] + delta;
                    max[1] = max[1] + delta;
                    max[2] = max[2] + delta;
                    return {
                        bottomLeft: min,
                        topRight: max
                    };
                }
                Molecule.getBox = getBox;
                var CentroidHelper = /** @class */ (function () {
                    function CentroidHelper(model) {
                        this.center = { x: 0, y: 0, z: 0 };
                        this.radiusSquared = 0;
                        this.count = 0;
                        this.x = model.positions.x;
                        this.y = model.positions.y;
                        this.z = model.positions.z;
                    }
                    CentroidHelper.prototype.addAtom = function (i) {
                        this.count++;
                        this.center.x += this.x[i];
                        this.center.y += this.y[i];
                        this.center.z += this.z[i];
                    };
                    CentroidHelper.prototype.finishedAdding = function () {
                        this.center.x /= this.count;
                        this.center.y /= this.count;
                        this.center.z /= this.count;
                    };
                    CentroidHelper.prototype.radiusVisit = function (i) {
                        var dx = this.center.x - this.x[i], dy = this.center.y - this.y[i], dz = this.center.z - this.z[i];
                        this.radiusSquared = Math.max(this.radiusSquared, dx * dx + dy * dy + dz * dz);
                    };
                    return CentroidHelper;
                }());
                Molecule.CentroidHelper = CentroidHelper;
                function getCentroidAndRadius(m, indices, into) {
                    LA.Vector3.set(into, 0, 0, 0);
                    var _a = m.positions, x = _a.x, y = _a.y, z = _a.z;
                    if (indices.length === 0)
                        return 0;
                    if (indices.length === 1) {
                        LA.Vector3.set(into, x[indices[0]], y[indices[0]], z[indices[0]]);
                        return 0;
                    }
                    for (var _i = 0, indices_12 = indices; _i < indices_12.length; _i++) {
                        var i = indices_12[_i];
                        into[0] += x[i];
                        into[1] += y[i];
                        into[2] += z[i];
                    }
                    var c = indices.length;
                    into[0] /= c;
                    into[1] /= c;
                    into[2] /= c;
                    var radius = 0;
                    for (var _c = 0, indices_13 = indices; _c < indices_13.length; _c++) {
                        var i = indices_13[_c];
                        var dx = into[0] - x[i], dy = into[1] - y[i], dz = into[2] - z[i];
                        radius = Math.max(radius, dx * dx + dy * dy + dz * dz);
                    }
                    return Math.sqrt(radius);
                }
                Molecule.getCentroidAndRadius = getCentroidAndRadius;
                Molecule.Labels3DKinds = ['Residue-Name', 'Residue-Full-Id', 'Atom-Name', 'Atom-Element'];
                Molecule.Labels3DKindLabels = {
                    'Residue-Name': 'Residue Name',
                    'Residue-Full-Id': 'Residue Full Id',
                    'Atom-Name': 'Atom Name',
                    'Atom-Element': 'Atom Element'
                };
                function labelProvider(options, model) {
                    var _a = model.data.atoms, residueIndex = _a.residueIndex, chainIndex = _a.chainIndex, name = _a.name, elementSymbol = _a.elementSymbol;
                    var _c = model.data.residues, residueName = _c.name, seqNumber = _c.seqNumber;
                    var authAsymId = model.data.chains.authAsymId;
                    switch (options.kind) {
                        case 'Residue-Name': return function (i) { return residueName[residueIndex[i]]; };
                        case 'Residue-Full-Id': return function (i) {
                            var r = residueIndex[i], c = chainIndex[i];
                            return residueName[r] + " " + authAsymId[c] + " " + seqNumber[r];
                        };
                        case 'Atom-Name': return function (i) { return name[i]; };
                        case 'Atom-Element': return function (i) { return elementSymbol[i]; };
                        default: return function (i) { return "" + i; };
                    }
                }
                function create3DLabelsParams(entity, options, theme) {
                    var ctx = findQueryContext(entity);
                    var query = options.kind.indexOf('Residue') >= 0 ? LiteMol.Core.Structure.Query.residues() : LiteMol.Core.Structure.Query.allAtoms();
                    var fs = query.compile()(ctx);
                    var label = labelProvider(options, ctx.structure);
                    var positions = LiteMol.Core.Utils.DataTable.ofDefinition(LiteMol.Core.Structure.Tables.Positions, fs.length);
                    var x = positions.x, y = positions.y, z = positions.z;
                    var labels = [];
                    var sizes = new Float32Array(fs.length);
                    var center = LA.Vector3.zero();
                    var i = 0;
                    for (var _i = 0, _a = fs.fragments; _i < _a.length; _i++) {
                        var f = _a[_i];
                        var l = label(f.atomIndices[0]);
                        getCentroidAndRadius(ctx.structure, f.atomIndices, center);
                        x[i] = center[0];
                        y[i] = center[1];
                        z[i] = center[2];
                        labels[labels.length] = l;
                        sizes[i] = 1.0;
                        i++;
                    }
                    return {
                        labels: labels,
                        options: options.labelsOptions,
                        positions: positions,
                        sizes: sizes,
                        theme: theme
                    };
                }
                Molecule.create3DLabelsParams = create3DLabelsParams;
            })(Molecule = Utils.Molecule || (Utils.Molecule = {}));
        })(Utils = Bootstrap.Utils || (Bootstrap.Utils = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            "use strict";
            var Streams = /** @class */ (function () {
                function Streams(context) {
                    this.context = context;
                    this.subjects = {
                        select: new Bootstrap.Rx.BehaviorSubject(Bootstrap.Interactivity.Info.empty),
                        click: new Bootstrap.Rx.BehaviorSubject(Bootstrap.Interactivity.Info.empty),
                        currentEntity: new Bootstrap.Rx.BehaviorSubject(void 0)
                    };
                    this.select = this.subjects.select.distinctUntilChanged(function (i) { return i; }, Bootstrap.Interactivity.interactivityInfoEqual);
                    this.click = this.subjects.click.distinctUntilChanged(function (i) { return i; }, Bootstrap.Interactivity.interactivityInfoEqual);
                    this.currentEntity = this.subjects.currentEntity;
                    this.init();
                }
                Streams.prototype.init = function () {
                    var _this = this;
                    var latestClick = Bootstrap.Interactivity.Info.empty;
                    Bootstrap.Event.Tree.NodeRemoved.getStream(this.context).subscribe(function (e) {
                        if (Bootstrap.Interactivity.isSelection(latestClick) && latestClick.source === e.data) {
                            latestClick = Bootstrap.Interactivity.Info.empty;
                            Bootstrap.Event.Visual.VisualSelectElement.dispatch(_this.context, latestClick);
                        }
                    });
                    Bootstrap.Event.Visual.VisualSelectElement.getStream(this.context).subscribe(function (e) {
                        latestClick = e.data;
                        _this.subjects.click.onNext(latestClick);
                        if (Bootstrap.Interactivity.isSelection(latestClick) && Bootstrap.Entity.isVisual(latestClick.source) && !latestClick.source.props.isSelectable)
                            return;
                        _this.subjects.select.onNext(latestClick);
                    });
                    Bootstrap.Event.Entity.CurrentChanged.getStream(this.context).subscribe(function (e) { return _this.subjects.currentEntity.onNext(e.data); });
                };
                return Streams;
            }());
            Behaviour.Streams = Streams;
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            "use strict";
            //////////////////////////////////////////////////
            function SetEntityToCurrentWhenAdded(context) {
                Bootstrap.Event.Tree.NodeAdded.getStream(context).subscribe(function (ev) {
                    var e = ev.data;
                    if (e && (e.transform.isUpdate || e.type.info.traits.isSilent))
                        return;
                    Bootstrap.Command.Entity.SetCurrent.dispatch(context, e);
                });
            }
            Behaviour.SetEntityToCurrentWhenAdded = SetEntityToCurrentWhenAdded;
            /** An ugly hack that will be removed when the time comes */
            Behaviour.SuppressCreateVisualWhenModelIsAdded = false;
            function CreateVisualWhenModelIsAdded(context) {
                Bootstrap.Event.Tree.NodeAdded.getStream(context).subscribe(function (e) {
                    if (Behaviour.SuppressCreateVisualWhenModelIsAdded || !Bootstrap.Tree.Node.is(e.data, Bootstrap.Entity.Molecule.Model) || e.data.isHidden) {
                        return;
                    }
                    var prms = Bootstrap.Entity.Transformer.Molecule.CreateMacromoleculeVisual.info.defaultParams(context, e.data);
                    Bootstrap.Command.Tree.ApplyTransform.dispatch(context, { node: e.data, transform: Bootstrap.Entity.Transformer.Molecule.CreateMacromoleculeVisual.create(prms) });
                });
            }
            Behaviour.CreateVisualWhenModelIsAdded = CreateVisualWhenModelIsAdded;
            function ApplySelectionToVisual(context) {
                Bootstrap.Event.Tree.NodeAdded.getStream(context).subscribe(function (ev) {
                    var e = ev.data;
                    if (Bootstrap.Entity.isMoleculeSelection(e) && Bootstrap.Entity.isVisual(e.parent)) {
                        var s = e;
                        var v = e.parent;
                        v.props.model.applySelection(s.props.indices, 1 /* Select */);
                    }
                });
                Bootstrap.Event.Tree.NodeRemoved.getStream(context).subscribe(function (ev) {
                    var e = ev.data;
                    if (Bootstrap.Entity.isMoleculeSelection(e) && Bootstrap.Entity.isVisual(e.parent)) {
                        var s = e;
                        var v = e.parent;
                        v.props.model.applySelection(s.props.indices, 2 /* RemoveSelect */);
                    }
                });
            }
            Behaviour.ApplySelectionToVisual = ApplySelectionToVisual;
            function _applyInteractivitySelection(stream, context) {
                var latestIndices = void 0;
                var latestModel = void 0;
                stream.subscribe(function (info) {
                    if (latestModel) {
                        latestModel.applySelection(latestIndices, 2 /* RemoveSelect */);
                        latestModel = void 0;
                        latestIndices = void 0;
                    }
                    if (Bootstrap.Interactivity.isEmpty(info) || !Bootstrap.Entity.isVisual(info.source))
                        return;
                    latestModel = info.source.props.model;
                    latestIndices = info.elements;
                    latestModel.applySelection(latestIndices, 1 /* Select */);
                });
            }
            function ApplyInteractivitySelection(context) {
                _applyInteractivitySelection(context.behaviours.click, context);
            }
            Behaviour.ApplyInteractivitySelection = ApplyInteractivitySelection;
            function FilteredApplyInteractivitySelection(filter) {
                return function (context) {
                    _applyInteractivitySelection(context.behaviours.click.filter(function (e) { return filter(e, context); }), context);
                };
            }
            Behaviour.FilteredApplyInteractivitySelection = FilteredApplyInteractivitySelection;
            function UnselectElementOnRepeatedClick(context) {
                var latest = Bootstrap.Interactivity.Info.empty;
                Bootstrap.Event.Visual.VisualSelectElement.getStream(context).subscribe(function (e) {
                    if (Bootstrap.Interactivity.isEmpty(e.data) || Bootstrap.Interactivity.isEmpty(latest)) {
                        latest = e.data;
                        return;
                    }
                    if ((Bootstrap.Tree.Node.hasAncestor(latest.source, e.data.source) || Bootstrap.Tree.Node.hasAncestor(e.data.source, latest.source)) && Bootstrap.Interactivity.interactivitySelectionElementsEqual(e.data, latest)) {
                        latest = Bootstrap.Interactivity.Info.empty;
                        setTimeout(function () { return Bootstrap.Event.Visual.VisualSelectElement.dispatch(context, Bootstrap.Interactivity.Info.empty); }, 0);
                    }
                    else {
                        latest = e.data;
                    }
                });
            }
            Behaviour.UnselectElementOnRepeatedClick = UnselectElementOnRepeatedClick;
            var center = LiteMol.Core.Geometry.LinearAlgebra.Vector3.zero();
            function updateCameraModel(context, info) {
                var model = Bootstrap.Utils.Molecule.findModel(info.source).props.model;
                if (!model)
                    return;
                var elems = info.elements;
                if (info.elements.length === 1) {
                    elems = Bootstrap.Utils.Molecule.getResidueIndices(model, info.elements[0]);
                }
                var radius = Bootstrap.Utils.Molecule.getCentroidAndRadius(model, elems, center);
                if (info.elements.length === 1) {
                    var a = info.elements[0];
                    center[0] = model.positions.x[a];
                    center[1] = model.positions.y[a];
                    center[2] = model.positions.z[a];
                }
                context.scene.camera.focusOnPoint(LiteMol.Core.Geometry.LinearAlgebra.Vector3.toObj(center), Math.max(radius, 7));
            }
            function updateCameraVisual(context, info) {
                if (Bootstrap.Interactivity.isEmpty(info) || info.source.type.info.typeClass !== 'Visual')
                    return;
                var v = info.source;
                var m = v.props.model;
                if (!m)
                    return;
                var bs = m.getBoundingSphereOfSelection(info.elements);
                if (bs) {
                    context.scene.camera.focusOnPoint(LiteMol.Core.Geometry.LinearAlgebra.Vector3.toObj(bs.center), Math.max(bs.radius, 7));
                }
                else {
                    context.scene.camera.focusOnModel(m);
                }
            }
            function focusCamera(stream, context) {
                stream.subscribe(function (e) {
                    if (Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(e))
                        updateCameraModel(context, e);
                    else
                        updateCameraVisual(context, e);
                });
            }
            function FocusCameraOnSelect(context) {
                focusCamera(context.behaviours.click, context);
            }
            Behaviour.FocusCameraOnSelect = FocusCameraOnSelect;
            function FilteredFocusCameraOnSelect(filter) {
                return function (context) {
                    focusCamera(context.behaviours.click.filter(function (e) { return filter(e, context); }), context);
                };
            }
            Behaviour.FilteredFocusCameraOnSelect = FilteredFocusCameraOnSelect;
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                var Query = LiteMol.Core.Structure.Query;
                var Transforms = Bootstrap.Entity.Transformer;
                /** An ugly hack that will be removed when the time comes */
                Molecule.SuppressShowInteractionOnSelect = false;
                function ShowInteractionOnSelect(radius) {
                    return function (context) {
                        var lastRef = void 0;
                        var ambRef = void 0;
                        var ligandStyle = {
                            type: 'BallsAndSticks',
                            taskType: 'Silent',
                            params: { useVDW: true, vdwScaling: 0.25, bondRadius: 0.13, detail: 'Automatic' },
                            theme: { template: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate, colors: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate.colors.set('Bond', LiteMol.Visualization.Theme.Default.SelectionColor), transparency: { alpha: 0.4 } },
                            isNotSelectable: true
                        };
                        var ambStyle = {
                            type: 'BallsAndSticks',
                            taskType: 'Silent',
                            params: { useVDW: false, atomRadius: 0.15, bondRadius: 0.07, detail: 'Automatic' },
                            theme: { template: Bootstrap.Visualization.Molecule.Default.UniformThemeTemplate, colors: Bootstrap.Visualization.Molecule.Default.UniformThemeTemplate.colors.set('Uniform', { r: 0.4, g: 0.4, b: 0.4 }), transparency: { alpha: 0.75 } },
                            isNotSelectable: true
                        };
                        function clean() {
                            if (lastRef) {
                                Bootstrap.Command.Tree.RemoveNode.dispatch(context, lastRef);
                                lastRef = void 0;
                                ambRef = void 0;
                            }
                        }
                        context.behaviours.click.subscribe(function (info) {
                            if (Molecule.SuppressShowInteractionOnSelect || Bootstrap.Interactivity.isEmpty(info)) {
                                clean();
                                return;
                            }
                            if (info.source.ref === ambRef) {
                                var model = Bootstrap.Utils.Molecule.findModel(info.source);
                                if (!model)
                                    return;
                                var query = Query.atomsFromIndices(info.elements);
                                setTimeout(Bootstrap.Command.Molecule.CreateSelectInteraction.dispatch(context, { entity: model, query: query }), 0);
                                return;
                            }
                            var isSelectable = Bootstrap.Entity.isVisual(info.source) ? info.source.props.isSelectable : true;
                            if (!isSelectable)
                                return;
                            clean();
                            if (Bootstrap.Interactivity.isEmpty(info) || !Bootstrap.Utils.Molecule.findModelOrSelection(info.source))
                                return;
                            var ligandQ = Query.atomsFromIndices(info.elements).wholeResidues();
                            var ambQ = Query.atomsFromIndices(info.elements).wholeResidues().ambientResidues(radius);
                            var ref = Bootstrap.Utils.generateUUID();
                            var action = Bootstrap.Tree.Transform.build().add(info.source, Transforms.Basic.CreateGroup, { label: 'Interaction' }, { ref: ref, isHidden: true });
                            lastRef = ref;
                            ambRef = Bootstrap.Utils.generateUUID();
                            action.then(Transforms.Molecule.CreateSelectionFromQuery, { query: ambQ, name: 'Ambience', silent: true, inFullContext: true }, { isBinding: true })
                                .then(Transforms.Molecule.CreateVisual, { style: ambStyle }, { ref: ambRef });
                            action.then(Transforms.Molecule.CreateSelectionFromQuery, { query: ligandQ, name: 'Ligand', silent: true, inFullContext: true }, { isBinding: true })
                                .then(Transforms.Molecule.CreateVisual, { style: ligandStyle });
                            Bootstrap.Tree.Transform.apply(context, action).run();
                        });
                    };
                }
                Molecule.ShowInteractionOnSelect = ShowInteractionOnSelect;
                function HighlightElementInfo(context) {
                    context.highlight.addProvider(function (info) {
                        if (!Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(info))
                            return void 0;
                        var data = Bootstrap.Interactivity.Molecule.transformInteraction(info);
                        return Bootstrap.Interactivity.Molecule.formatInfo(data);
                    });
                }
                Molecule.HighlightElementInfo = HighlightElementInfo;
                function DistanceToLastClickedElement(context) {
                    var lastInfo = Bootstrap.Interactivity.Info.empty;
                    var lastSel = void 0;
                    var lastModel = void 0;
                    context.behaviours.click.subscribe(function (info) {
                        if (!Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(info)) {
                            lastInfo = Bootstrap.Interactivity.Info.empty;
                            lastModel = void 0;
                            lastSel = void 0;
                        }
                        else {
                            lastInfo = info;
                            var m = Bootstrap.Utils.Molecule.findModel(info.source);
                            if (!m) {
                                lastInfo = Bootstrap.Interactivity.Info.empty;
                                lastModel = void 0;
                                lastSel = void 0;
                            }
                            else {
                                lastModel = m.props.model;
                                lastSel = Bootstrap.Interactivity.Molecule.formatInfoShort(Bootstrap.Interactivity.Molecule.transformInteraction(info));
                            }
                        }
                    });
                    context.highlight.addProvider(function (info) {
                        if (!Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(info))
                            return void 0;
                        if (Bootstrap.Interactivity.isEmpty(lastInfo))
                            return void 0;
                        var m = Bootstrap.Utils.Molecule.findModel(info.source);
                        if (!m)
                            return void 0;
                        var dist = Bootstrap.Utils.Molecule.getDistanceSet(lastModel, lastInfo.elements, m.props.model, info.elements);
                        if (dist < 0.0001)
                            return void 0;
                        return "<span><b>" + Bootstrap.Utils.round(dist, 2) + " \u212B</b> from <b>" + lastSel + "</b></span>";
                    });
                }
                Molecule.DistanceToLastClickedElement = DistanceToLastClickedElement;
            })(Molecule = Behaviour.Molecule || (Behaviour.Molecule = {}));
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            var Density;
            (function (Density) {
                "use strict";
                var ToastKey = '__ShowDynamicDensity-toast';
                var ShowDynamicDensity = /** @class */ (function () {
                    function ShowDynamicDensity(context, params) {
                        this.context = context;
                        this.params = params;
                        this.obs = [];
                        this.ref = Bootstrap.Utils.generateUUID();
                    }
                    ShowDynamicDensity.prototype.remove = function () {
                        var v = this.getVisual();
                        if (v) {
                            Bootstrap.Tree.remove(v);
                        }
                    };
                    ShowDynamicDensity.prototype.getVisual = function () {
                        return this.context.select(this.ref)[0];
                    };
                    ShowDynamicDensity.prototype.update = function (info) {
                        if (!this.params.showFull && !Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(info)) {
                            this.remove();
                            return;
                        }
                        Bootstrap.Command.Toast.Hide.dispatch(this.context, { key: ToastKey });
                        var style = Bootstrap.Utils.shallowClone(this.params.style);
                        style.params = Bootstrap.Utils.shallowClone(style.params);
                        if (this.params.showFull) {
                            style.params.bottomLeft = void 0;
                            style.params.topRight = void 0;
                            style.taskType = 'Normal';
                        }
                        else {
                            var i = info;
                            var model = Bootstrap.Utils.Molecule.findModel(i.source);
                            var elems = i.elements;
                            var m = model.props.model;
                            if (i.elements.length === 1) {
                                elems = Bootstrap.Utils.Molecule.getResidueIndices(m, i.elements[0]);
                            }
                            var box = Bootstrap.Utils.Molecule.getBox(m, elems, this.params.radius);
                            style.params.bottomLeft = box.bottomLeft;
                            style.params.topRight = box.topRight;
                            style.taskType = 'Silent';
                        }
                        var task;
                        var visual = this.getVisual();
                        if (!visual) {
                            var t = Bootstrap.Entity.Transformer.Density.CreateVisual.create({ style: style }, { ref: this.ref, isHidden: true });
                            t.isUpdate = true;
                            task = t.apply(this.context, this.behaviour);
                        }
                        else
                            task = Bootstrap.Entity.Transformer.Density.CreateVisual.create({ style: style }, { ref: this.ref, isHidden: true }).update(this.context, visual);
                        task.run();
                    };
                    ShowDynamicDensity.prototype.updateTheme = function (ti) {
                        this.params.style.theme = ti;
                        if (!this.behaviour)
                            return;
                        var v = this.getVisual();
                        if (!v)
                            return;
                        var source = Bootstrap.Tree.Node.findClosestNodeOfType(this.behaviour, [Bootstrap.Entity.Density.Data]);
                        var theme = ti.template.provider(source, Bootstrap.Visualization.Theme.getProps(ti));
                        v.props.model.applyTheme(theme);
                    };
                    ShowDynamicDensity.prototype.dispose = function () {
                        this.remove();
                        Bootstrap.Command.Toast.Hide.dispatch(this.context, { key: ToastKey });
                        for (var _i = 0, _a = this.obs; _i < _a.length; _i++) {
                            var o = _a[_i];
                            o.dispose();
                        }
                        this.obs = [];
                    };
                    ShowDynamicDensity.prototype.register = function (behaviour) {
                        var _this = this;
                        this.behaviour = behaviour;
                        if (!this.params.showFull) {
                            Bootstrap.Command.Toast.Show.dispatch(this.context, { key: ToastKey, title: 'Density', message: 'Click on a residue or an atom to view the data.', timeoutMs: 30 * 1000 });
                        }
                        this.obs.push(this.context.behaviours.select.subscribe(function (e) {
                            _this.update(e);
                        }));
                    };
                    return ShowDynamicDensity;
                }());
                Density.ShowDynamicDensity = ShowDynamicDensity;
            })(Density = Behaviour.Density || (Behaviour.Density = {}));
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            var Molecule;
            (function (Molecule) {
                "use strict";
                var Transforms = Bootstrap.Entity.Transformer;
                var CoordinateStreaming = /** @class */ (function () {
                    function CoordinateStreaming(context, server, radius) {
                        if (radius === void 0) { radius = 5; }
                        this.context = context;
                        this.radius = radius;
                        this.obs = [];
                        this.target = void 0;
                        this.behaviour = void 0;
                        this.ref = Bootstrap.Utils.generateUUID();
                        this.download = void 0;
                        this.cache = Bootstrap.Utils.LRUCache.create(100);
                        this.style = {
                            type: 'BallsAndSticks',
                            taskType: 'Silent',
                            params: { useVDW: true, vdwScaling: 0.17, bondRadius: 0.07, detail: 'Automatic' },
                            theme: { template: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate, colors: Bootstrap.Visualization.Molecule.Default.ElementSymbolThemeTemplate.colors, transparency: { alpha: 1.0 } },
                            isNotSelectable: true
                        };
                        this.server = CoordinateStreaming.normalizeServerName(server);
                    }
                    CoordinateStreaming.prototype.remove = function () {
                        if (this.download) {
                            this.download.tryAbort();
                            this.download = void 0;
                        }
                        Bootstrap.Command.Tree.RemoveNode.dispatch(this.context, this.ref);
                    };
                    CoordinateStreaming.prototype.isApplicable = function (info) {
                        if (!Bootstrap.Interactivity.Molecule.isMoleculeModelInteractivity(info))
                            return false;
                        return Bootstrap.Tree.Node.hasAncestor(info.source, this.target);
                    };
                    CoordinateStreaming.prototype.update = function (info) {
                        var _this = this;
                        this.remove();
                        if (!this.isApplicable(info)) {
                            return;
                        }
                        var model = Bootstrap.Utils.Molecule.findModel(info.source).props.model;
                        var i = model.data.atoms.residueIndex[info.elements[0]];
                        var rs = model.data.residues;
                        var authAsymId = rs.authAsymId[i];
                        var transform = void 0;
                        if (model.source === LiteMol.Core.Structure.Molecule.Model.Source.Computed) {
                            var p = model.parent;
                            var cI = rs.chainIndex[i];
                            var chain = model.data.chains.sourceChainIndex[cI];
                            authAsymId = p.data.chains.authAsymId[chain];
                            transform = model.operators[model.data.chains.operatorIndex[cI]].matrix;
                        }
                        var url = this.server + "/"
                            + (model.id.toLocaleLowerCase() + "/ambientResidues?")
                            + ("modelId=" + encodeURIComponent(model.modelId) + "&")
                            + ("entityId=" + encodeURIComponent(rs.entityId[i]) + "&")
                            + ("authAsymId=" + encodeURIComponent(authAsymId) + "&")
                            + ("authSeqNumber=" + encodeURIComponent('' + rs.authSeqNumber[i]) + "&")
                            + ("insCode=" + encodeURIComponent(rs.insCode[i] !== null ? rs.insCode[i] : '') + "&")
                            + ("radius=" + encodeURIComponent('' + this.radius) + "&")
                            + "atomSitesOnly=1&"
                            + "encoding=bcif&"
                            + "lowPrecisionCoords=1";
                        this.download = Bootstrap.Utils.ajaxGetArrayBuffer(url).runWithContext(this.context);
                        var cached = Bootstrap.Utils.LRUCache.get(this.cache, url);
                        if (cached) {
                            this.create(cached, transform);
                        }
                        else {
                            this.context.performance.start(this.ref);
                            this.download.result.then(function (data) {
                                Bootstrap.Utils.LRUCache.set(_this.cache, url, data);
                                _this.context.performance.end(_this.ref);
                                _this.context.logger.info("Streaming done in " + _this.context.performance.formatTime(_this.ref));
                                _this.create(data, transform);
                            }).catch(function () { _this.context.performance.end(_this.ref); });
                        }
                    };
                    CoordinateStreaming.prototype.create = function (data, transform) {
                        var action = Bootstrap.Tree.Transform.build().add(this.behaviour, Bootstrap.Entity.Transformer.Molecule.CoordinateStreaming.CreateModel, { data: data, transform: transform }, { ref: this.ref, isHidden: true })
                            .then(Transforms.Molecule.CreateVisual, { style: this.style });
                        Bootstrap.Tree.Transform.apply(this.context, action).run();
                    };
                    CoordinateStreaming.prototype.dispose = function () {
                        this.remove();
                        for (var _i = 0, _a = this.obs; _i < _a.length; _i++) {
                            var o = _a[_i];
                            o.dispose();
                        }
                        this.obs = [];
                    };
                    CoordinateStreaming.prototype.register = function (behaviour) {
                        var _this = this;
                        this.behaviour = behaviour;
                        this.target = behaviour.parent;
                        this.obs.push(this.context.behaviours.select.subscribe(function (e) { return _this.update(e); }));
                    };
                    return CoordinateStreaming;
                }());
                Molecule.CoordinateStreaming = CoordinateStreaming;
                (function (CoordinateStreaming) {
                    function normalizeServerName(s) {
                        if (s[s.length - 1] !== '/')
                            return s;
                        if (s.length > 0)
                            return s.substr(0, s.length - 1);
                        return s;
                    }
                    CoordinateStreaming.normalizeServerName = normalizeServerName;
                    function getBaseUrl(id, server) {
                        return normalizeServerName(server) + "/" + id.trim().toLocaleLowerCase() + "/cartoon?encoding=bcif&lowPrecisionCoords=1";
                    }
                    CoordinateStreaming.getBaseUrl = getBaseUrl;
                })(CoordinateStreaming = Molecule.CoordinateStreaming || (Molecule.CoordinateStreaming = {}));
            })(Molecule = Behaviour.Molecule || (Behaviour.Molecule = {}));
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Behaviour;
        (function (Behaviour) {
            "use strict";
            function trackTransform(ctx, name, transformer, a, transform, selector, gaId) {
                if (transform.transformer !== transformer)
                    return;
                try {
                    var ga = window[gaId];
                    var p = selector(transform.params, a);
                    if (ga && typeof p !== 'undefined') {
                        ga('send', 'event', name, p, ctx.id);
                        //console.log('send', name, p, ctx.id);
                    }
                }
                catch (e) {
                    //console.log('error', e);
                }
            }
            function selectedMoleculeCreateFromData(p, a) { return p.format.name; }
            function selectDownload(p) { return p.url; }
            function selectQuery(p) { return p.queryString; }
            function selectAssembly(p, a) {
                if (Bootstrap.Tree.Node.isHidden(a))
                    return void 0;
                var m = Bootstrap.Utils.Molecule.findModel(a);
                if (!m)
                    return void 0;
                return m.props.model.id + ' $(name)$ ' + p.name;
            }
            function selectCrystalSymmetry(p, a) {
                if (Bootstrap.Tree.Node.isHidden(a))
                    return void 0;
                var m = Bootstrap.Utils.Molecule.findModel(a);
                if (!m)
                    return void 0;
                return m.props.model.id + ' $(type)$ ' + p.type + ' $(radius)$ ' + p.radius;
            }
            function selectStreaming(p, a) {
                var m = Bootstrap.Utils.Molecule.findModel(a);
                if (!m)
                    return void 0;
                return m.props.model.id + ' $(server)$ ' + p.server;
            }
            function selectVisual(p, a) {
                if (Bootstrap.Tree.Node.isHidden(a))
                    return void 0;
                return p.style.type;
            }
            function selectDensity(p) { return '$(format)$ ' + p.format; }
            function selectSelection(p, a) {
                return p.queryString;
            }
            function GoogleAnalytics(id, key) {
                if (key === void 0) { key = 'default'; }
                return function (context) {
                    var gaId = "ga-" + context.id + "-" + key;
                    try {
                        (function (i, s, o, g, r, a, m) {
                            i['GoogleAnalyticsObject'] = r;
                            i[r] = i[r] || function () {
                                (i[r].q = i[r].q || []).push(arguments);
                            }, i[r].l = 1 * (+new Date());
                            a = s.createElement(o),
                                m = s.getElementsByTagName(o)[0];
                            a.async = 1;
                            a.src = g;
                            m.parentNode.insertBefore(a, m);
                        })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', gaId);
                        window[gaId]('create', id, 'auto');
                        setTimeout(function () {
                            try {
                                var ga = window[gaId];
                                if (ga)
                                    ga('send', 'event', 'Loaded', 'contextId', context.id);
                            }
                            catch (e) { }
                        }, 1000);
                    }
                    catch (e) {
                    }
                    Bootstrap.Event.Tree.TransformerApply.getStream(context).subscribe(function (e) {
                        trackTransform(context, 'Download', Bootstrap.Entity.Transformer.Data.Download, e.data.a, e.data.t, selectDownload, gaId);
                        trackTransform(context, 'Create Molecule From Data', Bootstrap.Entity.Transformer.Molecule.CreateFromData, e.data.a, e.data.t, selectedMoleculeCreateFromData, gaId);
                        trackTransform(context, 'Create Model Selecion', Bootstrap.Entity.Transformer.Molecule.CreateSelection, e.data.a, e.data.t, selectQuery, gaId);
                        trackTransform(context, 'Create Assembly', Bootstrap.Entity.Transformer.Molecule.CreateAssembly, e.data.a, e.data.t, selectAssembly, gaId);
                        trackTransform(context, 'Create Symmetry', Bootstrap.Entity.Transformer.Molecule.CreateSymmetryMates, e.data.a, e.data.t, selectCrystalSymmetry, gaId);
                        trackTransform(context, 'Create Visual', Bootstrap.Entity.Transformer.Molecule.CreateVisual, e.data.a, e.data.t, selectVisual, gaId);
                        trackTransform(context, 'Coordinate Streaming', Bootstrap.Entity.Transformer.Molecule.CoordinateStreaming.CreateBehaviour, e.data.a, e.data.t, selectStreaming, gaId);
                        trackTransform(context, 'Parse Density', Bootstrap.Entity.Transformer.Density.ParseData, e.data.a, e.data.t, selectDensity, gaId);
                        trackTransform(context, 'Create Model Selection', Bootstrap.Entity.Transformer.Molecule.CreateSelection, e.data.a, e.data.t, selectSelection, gaId);
                    });
                };
            }
            Behaviour.GoogleAnalytics = GoogleAnalytics;
        })(Behaviour = Bootstrap.Behaviour || (Bootstrap.Behaviour = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            "use strict";
            var Component = /** @class */ (function () {
                function Component(context, initialState) {
                    this.context = context;
                    this._state = new Bootstrap.Rx.Subject();
                    this._latestState = void 0;
                    this._latestState = initialState;
                }
                Object.defineProperty(Component.prototype, "dispatcher", {
                    get: function () {
                        return this.context.dispatcher;
                    },
                    enumerable: true,
                    configurable: true
                });
                Component.prototype.setState = function () {
                    var states = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        states[_i] = arguments[_i];
                    }
                    var s = Bootstrap.Utils.merge.apply(Bootstrap.Utils, [this._latestState].concat(states));
                    if (s !== this._latestState) {
                        this._latestState = s;
                        this._state.onNext(s);
                    }
                };
                Object.defineProperty(Component.prototype, "state", {
                    get: function () {
                        return this._state;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(Component.prototype, "latestState", {
                    get: function () {
                        return this._latestState;
                    },
                    enumerable: true,
                    configurable: true
                });
                return Component;
            }());
            Components.Component = Component;
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            "use strict";
            var LayoutRegion;
            (function (LayoutRegion) {
                LayoutRegion[LayoutRegion["Main"] = 0] = "Main";
                LayoutRegion[LayoutRegion["Top"] = 1] = "Top";
                LayoutRegion[LayoutRegion["Right"] = 2] = "Right";
                LayoutRegion[LayoutRegion["Bottom"] = 3] = "Bottom";
                LayoutRegion[LayoutRegion["Left"] = 4] = "Left";
                LayoutRegion[LayoutRegion["Root"] = 5] = "Root";
            })(LayoutRegion = Components.LayoutRegion || (Components.LayoutRegion = {}));
            var CollapsedControlsLayout;
            (function (CollapsedControlsLayout) {
                CollapsedControlsLayout[CollapsedControlsLayout["Outside"] = 0] = "Outside";
                CollapsedControlsLayout[CollapsedControlsLayout["Landscape"] = 1] = "Landscape";
                CollapsedControlsLayout[CollapsedControlsLayout["Portrait"] = 2] = "Portrait";
            })(CollapsedControlsLayout = Components.CollapsedControlsLayout || (Components.CollapsedControlsLayout = {}));
            var LayoutTarget = /** @class */ (function () {
                function LayoutTarget(cssClass) {
                    this.cssClass = cssClass;
                    this.components = [];
                }
                return LayoutTarget;
            }());
            Components.LayoutTarget = LayoutTarget;
            function makeEmptyTargets() {
                var ret = [];
                for (var i = 0; i <= LayoutRegion.Root; i++) {
                    ret.push(new LayoutTarget(LayoutRegion[i].toLowerCase()));
                }
                return ret;
            }
            Components.makeEmptyTargets = makeEmptyTargets;
            var Layout = /** @class */ (function (_super) {
                __extends(Layout, _super);
                function Layout(context, targets, root) {
                    var _this = _super.call(this, context, {
                        isExpanded: false,
                        hideControls: false,
                        collapsedControlsLayout: CollapsedControlsLayout.Outside,
                        regionStates: {}
                    }) || this;
                    _this.targets = targets;
                    _this.root = root;
                    _this.rootState = void 0;
                    Bootstrap.Command.Layout.SetState.getStream(_this.context).subscribe(function (e) { return _this.update(e.data); });
                    // <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
                    _this.expandedViewport = document.createElement('meta');
                    _this.expandedViewport.name = 'viewport';
                    _this.expandedViewport.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0';
                    return _this;
                }
                Layout.prototype.update = function (state) {
                    var _this = this;
                    var prevExpanded = !!this.latestState.isExpanded;
                    this.setState(state);
                    if (typeof state.isExpanded === "boolean" && state.isExpanded !== prevExpanded)
                        this.handleExpand();
                    this.dispatcher.schedule(function () { return Bootstrap.Event.Common.LayoutChanged.dispatch(_this.context, {}); });
                };
                Layout.prototype.getScrollElement = function () {
                    if (document.scrollingElement)
                        return document.scrollingElement;
                    if (document.documentElement)
                        return document.documentElement;
                    return document.body;
                };
                Layout.prototype.handleExpand = function () {
                    try {
                        var body = document.getElementsByTagName('body')[0];
                        var head = document.getElementsByTagName('head')[0];
                        if (!body || !head)
                            return;
                        if (this.latestState.isExpanded) {
                            var children = head.children;
                            var hasExp = false;
                            var viewports = [];
                            for (var i = 0; i < children.length; i++) {
                                if (children[i] === this.expandedViewport) {
                                    hasExp = true;
                                }
                                else if ((children[i].name || '').toLowerCase() === 'viewport') {
                                    viewports.push(children[i]);
                                }
                            }
                            for (var _i = 0, viewports_1 = viewports; _i < viewports_1.length; _i++) {
                                var v = viewports_1[_i];
                                head.removeChild(v);
                            }
                            if (!hasExp)
                                head.appendChild(this.expandedViewport);
                            var s = body.style;
                            var doc = this.getScrollElement();
                            var scrollLeft = doc.scrollLeft;
                            var scrollTop = doc.scrollTop;
                            this.rootState = {
                                top: s.top, bottom: s.bottom, right: s.right, left: s.left, scrollTop: scrollTop, scrollLeft: scrollLeft, position: s.position, overflow: s.overflow, viewports: viewports, zindex: this.root.style.zIndex,
                                width: s.width, height: s.height,
                                maxWidth: s.maxWidth, maxHeight: s.maxHeight,
                                margin: s.margin, marginLeft: s.marginLeft, marginRight: s.marginRight, marginTop: s.marginTop, marginBottom: s.marginBottom
                            };
                            s.overflow = 'hidden';
                            s.position = 'fixed';
                            s.top = "0";
                            s.bottom = "0";
                            s.right = "0";
                            s.left = "0";
                            s.width = "100%";
                            s.height = "100%";
                            s.maxWidth = "100%";
                            s.maxHeight = "100%";
                            s.margin = "0";
                            s.marginLeft = "0";
                            s.marginRight = "0";
                            s.marginTop = "0";
                            s.marginBottom = "0";
                            this.root.style.zIndex = "100000";
                        }
                        else {
                            //root.style.overflow = rootOverflow;
                            var children = head.children;
                            for (var i = 0; i < children.length; i++) {
                                if (children[i] === this.expandedViewport) {
                                    head.removeChild(this.expandedViewport);
                                    break;
                                }
                            }
                            if (this.rootState) {
                                var s = body.style, t = this.rootState;
                                for (var _a = 0, _b = t.viewports; _a < _b.length; _a++) {
                                    var v = _b[_a];
                                    head.appendChild(v);
                                }
                                s.top = t.top;
                                s.bottom = t.bottom;
                                s.left = t.left;
                                s.right = t.right;
                                s.width = t.width;
                                s.height = t.height;
                                s.maxWidth = t.maxWidth;
                                s.maxHeight = t.maxHeight;
                                s.margin = t.margin;
                                s.marginLeft = t.marginLeft;
                                s.marginRight = t.marginRight;
                                s.marginTop = t.marginTop;
                                s.marginBottom = t.marginBottom;
                                s.position = t.position;
                                s.overflow = t.overflow;
                                var doc = this.getScrollElement();
                                doc.scrollTop = t.scrollTop;
                                doc.scrollLeft = t.scrollLeft;
                                this.rootState = void 0;
                                this.root.style.zIndex = t.zindex;
                            }
                        }
                    }
                    catch (e) {
                        this.context.logger.error('Layout change error, you might have to reload the page.');
                        console.log('Layout change error, you might have to reload the page.', e);
                    }
                };
                Layout.prototype.updateTargets = function (targets) {
                    var _this = this;
                    this.targets = targets;
                    this.dispatcher.schedule(function () { return Bootstrap.Event.Common.ComponentsChanged.dispatch(_this.context, {}); });
                };
                return Layout;
            }(Components.Component));
            Components.Layout = Layout;
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Transform;
            (function (Transform) {
                "use strict";
                var Controller = /** @class */ (function (_super) {
                    __extends(Controller, _super);
                    function Controller(context, transformer, entity) {
                        var _this = _super.call(this, context, {
                            params: transformer.info.defaultParams(context, entity),
                            canApply: false,
                            isBusy: false,
                            issues: void 0,
                            parametersAutoUpdating: false,
                            isDirty: false
                        }) || this;
                        _this.transformer = transformer;
                        _this.entity = entity;
                        _this.updateTimeout = new Bootstrap.Rx.Subject();
                        _this.timeout = Bootstrap.Rx.Observable.timer(50);
                        _this.never = Bootstrap.Rx.Observable.never();
                        _this.anchorParams = _this.latestState.params;
                        _this.updateParams(_this.anchorParams);
                        _this.updateTimeout.flatMapLatest(function (t) { return t; }).forEach(function () { return _this.apply(); });
                        return _this;
                    }
                    Controller.prototype._update = function () {
                        if (this.isUpdate && !this.latestState.isBusy) {
                            if (this.updateTimeout) {
                                this.updateTimeout.onNext(this.timeout);
                                this.setState({ parametersAutoUpdating: true });
                            }
                        }
                    };
                    Controller.prototype._reset = function () {
                        this.setState({ parametersAutoUpdating: false });
                        if (this.updateTimeout)
                            this.updateTimeout.onNext(this.never);
                    };
                    Controller.prototype._updateParams = function (params) {
                        var updated = Bootstrap.Utils.merge(this.latestState.params, params);
                        if (this.transformer.info.validateParams) {
                            var isInvalid = this.transformer.info.validateParams(updated);
                            if (isInvalid && isInvalid.length > 0) {
                                this.setState({ params: updated, issues: isInvalid, canApply: false });
                                return;
                            }
                        }
                        var isDirty = !Bootstrap.Utils.deepEqual(this.anchorParams, updated);
                        this.setState({ params: updated, isDirty: isDirty, issues: void 0, canApply: true });
                    };
                    Controller.prototype.updateParams = function (params) {
                        this._reset();
                        this._updateParams(params);
                    };
                    Controller.prototype.autoUpdateParams = function (params) {
                        this._update();
                        this._updateParams(params);
                    };
                    Object.defineProperty(Controller.prototype, "isUpdate", {
                        get: function () {
                            return this.transformer === this.entity.transform.transformer;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Controller.prototype.apply = function () {
                        var _this = this;
                        this._reset();
                        if (this.latestState.isBusy)
                            return;
                        var transform = this.transformer.create(this.latestState.params);
                        this.anchorParams = this.latestState.params;
                        this.setState({ isDirty: false, isBusy: true });
                        try {
                            var task = this.isUpdate ? transform.update(this.context, this.entity) : transform.apply(this.context, this.entity);
                            var ret = task.run();
                            ret.then(function () { return _this.setState({ isBusy: false }); }).catch(function () { return _this.setState({ isBusy: false }); });
                            return ret;
                        }
                        catch (e) {
                            this.setState({ isBusy: false });
                            return LiteMol.Core.Computation.reject(e);
                        }
                    };
                    Controller.prototype.setParams = function (params) {
                        this._reset();
                        this.anchorParams = params;
                        this.updateParams(params);
                    };
                    return Controller;
                }(Components.Component));
                Transform.Controller = Controller;
            })(Transform = Components.Transform || (Components.Transform = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Transform;
            (function (Transform) {
                "use strict";
                var View = /** @class */ (function (_super) {
                    __extends(View, _super);
                    function View(context) {
                        var _this = _super.call(this, context, { update: void 0, transforms: [] }) || this;
                        _this.update();
                        Bootstrap.Event.Entity.CurrentChanged.getStream(context).subscribe(function () { return _this.update(); });
                        return _this;
                    }
                    View.prototype.update = function () {
                        if (!this.context.currentEntity) {
                            this.setState({ transforms: [] });
                            return;
                        }
                        var e = this.context.currentEntity;
                        var manager = this.context.transforms;
                        var update = void 0;
                        if (e.transform.transformer && e.transform.transformer.info.isUpdatable /*&& !e.transform.props.isBinding*/) {
                            update = manager.getController(e.transform.transformer, e);
                        }
                        var transforms = [];
                        for (var _i = 0, _a = this.context.transforms.getBySourceType(e.type); _i < _a.length; _i++) {
                            var t = _a[_i];
                            if (t.info.isApplicable && !t.info.isApplicable(e)) {
                                continue;
                            }
                            var c = manager.getController(t, e);
                            if (c)
                                transforms.push(c);
                            //this.setParams(c);                
                        }
                        this.setState({ update: update, transforms: transforms });
                    };
                    return View;
                }(Components.Component));
                Transform.View = View;
            })(Transform = Components.Transform || (Components.Transform = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Transform;
            (function (Transform) {
                "use strict";
                var VisualStyle = /** @class */ (function (_super) {
                    __extends(VisualStyle, _super);
                    function VisualStyle() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    VisualStyle.prototype.updateTemplate = function (key, all) {
                        var s = all.get(key);
                        var latestTheme = this.latestState && this.latestState.params.style.theme;
                        var params = s.params;
                        var theme = latestTheme || this.getThemeInstance(s.theme.template);
                        var style = { type: s.type, params: params, theme: theme };
                        this.autoUpdateParams({ style: style });
                    };
                    VisualStyle.prototype.updateStyleParams = function (params) {
                        var s = Bootstrap.Utils.shallowClone(this.latestState.params.style);
                        s.params = Bootstrap.Utils.merge(s.params, params);
                        this.autoUpdateParams({ style: s });
                    };
                    VisualStyle.prototype.updateStyleTheme = function (theme) {
                        var s = Bootstrap.Utils.shallowClone(this.latestState.params.style);
                        s.theme = Bootstrap.Utils.merge(s.theme, theme);
                        this.autoUpdateParams({ style: s });
                    };
                    VisualStyle.prototype.updateThemeColor = function (name, value) {
                        var oldTheme = this.latestState.params.style.theme;
                        if (!oldTheme)
                            return;
                        var colors = oldTheme.colors;
                        if (!colors)
                            colors = Bootstrap.Immutable.Map();
                        colors = colors.set(name, value);
                        this.updateStyleTheme({ colors: colors });
                    };
                    VisualStyle.prototype.updateThemeVariable = function (name, value) {
                        var oldTheme = this.latestState.params.style.theme;
                        if (!oldTheme)
                            return;
                        var variables = oldTheme.variables;
                        if (!variables)
                            variables = Bootstrap.Immutable.Map();
                        variables = variables.set(name, value);
                        this.updateStyleTheme({ variables: variables });
                    };
                    VisualStyle.prototype.updateThemeTransparency = function (transparency) {
                        var oldTheme = this.latestState.params.style.theme;
                        if (!oldTheme)
                            return;
                        this.updateStyleTheme({ transparency: transparency });
                    };
                    VisualStyle.prototype.getThemeInstance = function (template) {
                        var oldTheme = this.latestState.params.style.theme;
                        var defaultTransparency = Bootstrap.Visualization.Molecule.Default.ForType.get(this.latestState.params.style.type).theme.transparency;
                        if (!oldTheme)
                            return { template: template, colors: template.colors, transparency: defaultTransparency };
                        var colors = template.colors;
                        if (oldTheme.colors && colors) {
                            colors = colors.withMutations(function (map) {
                                oldTheme.colors.forEach(function (c, n) {
                                    if (map.has(n))
                                        map.set(n, c);
                                });
                            });
                        }
                        var variables = template.variables;
                        if (oldTheme.variables && variables) {
                            variables = variables.withMutations(function (map) {
                                oldTheme.variables.forEach(function (c, n) {
                                    if (map.has(n))
                                        map.set(n, c);
                                });
                            });
                        }
                        var transparency = oldTheme.transparency ? oldTheme.transparency : defaultTransparency;
                        return { template: template, colors: colors, variables: variables, transparency: transparency };
                    };
                    VisualStyle.prototype.updateThemeDefinition = function (definition) {
                        this.updateStyleTheme(this.getThemeInstance(definition));
                    };
                    return VisualStyle;
                }(Transform.Controller));
                Transform.VisualStyle = VisualStyle;
                var MoleculeVisual = /** @class */ (function (_super) {
                    __extends(MoleculeVisual, _super);
                    function MoleculeVisual() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    return MoleculeVisual;
                }(VisualStyle));
                Transform.MoleculeVisual = MoleculeVisual;
                var MoleculeLabels = /** @class */ (function (_super) {
                    __extends(MoleculeLabels, _super);
                    function MoleculeLabels() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    return MoleculeLabels;
                }(VisualStyle));
                Transform.MoleculeLabels = MoleculeLabels;
                var GenericLabels = /** @class */ (function (_super) {
                    __extends(GenericLabels, _super);
                    function GenericLabels() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    return GenericLabels;
                }(VisualStyle));
                Transform.GenericLabels = GenericLabels;
                var DensityVisual = /** @class */ (function (_super) {
                    __extends(DensityVisual, _super);
                    function DensityVisual() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    DensityVisual.prototype.cloneStyle = function (prop) {
                        return Bootstrap.Utils.shallowClone(this.latestState.params[prop || 'style']);
                    };
                    DensityVisual.prototype.getStyle = function (prop) {
                        return this.latestState.params[prop || 'style'];
                    };
                    DensityVisual.prototype.setStyle = function (style, prop) {
                        var _a;
                        this.autoUpdateParams((_a = {}, _a[prop || 'style'] = style, _a));
                    };
                    DensityVisual.prototype.updateStyleParams = function (params, styleProp) {
                        var s = this.cloneStyle(styleProp);
                        s.params = Bootstrap.Utils.merge(s.params, params);
                        this.setStyle(s, styleProp);
                    };
                    DensityVisual.prototype.updateStyleTheme = function (theme, styleProp) {
                        var s = this.cloneStyle(styleProp);
                        s.theme = Bootstrap.Utils.merge(s.theme, theme);
                        this.setStyle(s, styleProp);
                    };
                    DensityVisual.prototype.updateThemeColor = function (name, value, styleProp) {
                        var oldTheme = this.getStyle(styleProp).theme;
                        if (!oldTheme)
                            return;
                        var colors = oldTheme.colors;
                        if (!colors)
                            colors = Bootstrap.Immutable.Map();
                        colors = colors.set(name, value);
                        this.updateStyleTheme({ colors: colors }, styleProp);
                    };
                    DensityVisual.prototype.updateThemeTransparency = function (transparency, styleProp) {
                        var oldTheme = this.getStyle(styleProp).theme;
                        if (!oldTheme)
                            return;
                        this.updateStyleTheme({ transparency: transparency }, styleProp);
                    };
                    DensityVisual.prototype.getThemeInstance = function (template, styleProp) {
                        var oldTheme = this.getStyle(styleProp).theme;
                        var defaultTransparency = Bootstrap.Visualization.Density.Default.Transparency;
                        if (!oldTheme)
                            return { template: template, colors: template.colors, transparency: defaultTransparency };
                        var colors = template.colors;
                        if (oldTheme.colors && colors) {
                            colors = colors.withMutations(function (map) {
                                oldTheme.colors.forEach(function (c, n) {
                                    if (map.has(n))
                                        map.set(n, c);
                                });
                            });
                        }
                        var transparency = oldTheme.transparency ? oldTheme.transparency : defaultTransparency;
                        return { template: template, colors: colors, transparency: transparency };
                    };
                    DensityVisual.prototype.updateThemeDefinition = function (definition, styleProp) {
                        this.updateStyleTheme(this.getThemeInstance(definition, styleProp), styleProp);
                    };
                    return DensityVisual;
                }(Transform.Controller));
                Transform.DensityVisual = DensityVisual;
            })(Transform = Components.Transform || (Components.Transform = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Transform;
            (function (Transform) {
                "use strict";
                var Updater = /** @class */ (function (_super) {
                    __extends(Updater, _super);
                    function Updater(ctx, selector, header) {
                        var _this = _super.call(this, ctx, { controller: void 0 }) || this;
                        _this.selector = selector;
                        _this.header = header;
                        Bootstrap.Event.Tree.NodeAdded.getStream(ctx).subscribe(function () { return _this.added(); });
                        Bootstrap.Event.Tree.NodeRemoved.getStream(ctx).subscribe(function (e) { return _this.removed(e.data); });
                        return _this;
                    }
                    Updater.prototype.removed = function (e) {
                        if (!this.latestState.controller)
                            return;
                        var l = this.latestState.controller.entity;
                        if (l === e) {
                            this.setState({ controller: void 0 });
                        }
                    };
                    Updater.prototype.added = function () {
                        var sel = this.context.select(this.selector);
                        var e = sel[0];
                        if (!e || !e.transform)
                            return;
                        var c = this.context.transforms.getController(e.transform.transformer, e);
                        if (!c)
                            return;
                        this.setState({ controller: c });
                    };
                    return Updater;
                }(Components.Component));
                Transform.Updater = Updater;
            })(Transform = Components.Transform || (Components.Transform = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Transform;
            (function (Transform) {
                "use strict";
                var Action = /** @class */ (function (_super) {
                    __extends(Action, _super);
                    function Action(ctx, selector, transformer, header) {
                        var _this = _super.call(this, ctx, { controller: void 0 }) || this;
                        _this.selector = selector;
                        _this.transformer = transformer;
                        _this.header = header;
                        Bootstrap.Event.Tree.NodeAdded.getStream(ctx).subscribe(function () { return _this.added(); });
                        Bootstrap.Event.Tree.NodeRemoved.getStream(ctx).subscribe(function (e) { return _this.removed(e.data); });
                        return _this;
                    }
                    Action.prototype.removed = function (e) {
                        if (!this.latestState.controller)
                            return;
                        var l = this.latestState.controller.entity;
                        if (l === e) {
                            this.setState({ controller: void 0 });
                        }
                    };
                    Action.prototype.added = function () {
                        var sel = this.context.select(this.selector);
                        var e = sel[0];
                        if (!e)
                            return;
                        var c = this.context.transforms.getController(this.transformer, e);
                        if (!c)
                            return;
                        this.setState({ controller: c });
                    };
                    return Action;
                }(Components.Component));
                Transform.Action = Action;
            })(Transform = Components.Transform || (Components.Transform = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Context;
            (function (Context) {
                "use strict";
                var Log = /** @class */ (function (_super) {
                    __extends(Log, _super);
                    function Log(context) {
                        var _this = _super.call(this, context, { entries: Bootstrap.Immutable.List() }) || this;
                        Bootstrap.Event.Log.getStream(_this.context)
                            .subscribe(function (e) { return _this.setState({ entries: _this.latestState.entries.push(e.data) }); });
                        return _this;
                    }
                    return Log;
                }(Components.Component));
                Context.Log = Log;
            })(Context = Components.Context || (Components.Context = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Context;
            (function (Context) {
                "use strict";
                var Toast = /** @class */ (function (_super) {
                    __extends(Toast, _super);
                    function Toast(context) {
                        var _this = _super.call(this, context, { entries: Bootstrap.Immutable.Map() }) || this;
                        _this.serialNumber = 0;
                        _this.serialId = 0;
                        Bootstrap.Command.Toast.Show.getStream(_this.context).subscribe(function (e) { return _this.show(e.data); });
                        Bootstrap.Command.Toast.Hide.getStream(_this.context).subscribe(function (e) { return _this.hide(_this.findByKey(e.data.key)); });
                        return _this;
                    }
                    Toast.prototype.findByKey = function (key) {
                        return this.latestState.entries.find(function (e) { return !!e && e.key === key; });
                    };
                    Toast.prototype.show = function (toast) {
                        var _this = this;
                        var entries = this.latestState.entries;
                        var e = void 0;
                        var id = ++this.serialId;
                        var serialNumber;
                        if (toast.key && (e = this.findByKey(toast.key))) {
                            if (e.timeout !== void 0)
                                clearTimeout(e.timeout);
                            serialNumber = e.serialNumber;
                            entries = entries.remove(e.id);
                        }
                        else {
                            serialNumber = ++this.serialNumber;
                        }
                        e = {
                            id: id,
                            serialNumber: serialNumber,
                            key: toast.key,
                            title: toast.title,
                            message: toast.message,
                            timeout: this.timeout(id, toast.timeoutMs),
                            hide: function () { return _this.hideId(id); }
                        };
                        entries = entries.set(id, e);
                        this.setState({ entries: entries });
                    };
                    Toast.prototype.timeout = function (id, delay) {
                        var _this = this;
                        if (delay === void 0)
                            return void 0;
                        if (delay < 0)
                            delay = 500;
                        return setTimeout(function () {
                            var e = _this.latestState.entries.get(id);
                            e.timeout = void 0;
                            _this.hide(e);
                        }, delay);
                    };
                    Toast.prototype.hideId = function (id) {
                        this.hide(this.latestState.entries.get(id));
                    };
                    Toast.prototype.hide = function (e) {
                        if (!e)
                            return;
                        if (e.timeout !== void 0)
                            clearTimeout(e.timeout);
                        e.hide = void 0;
                        var entries = this.latestState.entries;
                        entries = entries.delete(e.id);
                        this.setState({ entries: entries });
                    };
                    return Toast;
                }(Components.Component));
                Context.Toast = Toast;
            })(Context = Components.Context || (Components.Context = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Context;
            (function (Context) {
                "use strict";
                var TaskWatcher = /** @class */ (function (_super) {
                    __extends(TaskWatcher, _super);
                    function TaskWatcher(context, type) {
                        var _this = _super.call(this, context, {
                            tasks: Bootstrap.Immutable.Map()
                        }) || this;
                        _this.type = type;
                        Bootstrap.Event.Task.StateUpdated.getStream(_this.context)
                            .subscribe(function (e) { return _this.updated(e.data); });
                        Bootstrap.Event.Task.Started.getStream(_this.context)
                            .filter(function (e) { return e.data.type === type; })
                            .subscribe(function (e) { return _this.started(e.data); });
                        Bootstrap.Event.Task.Completed.getStream(_this.context)
                            .subscribe(function (e) { return _this.completed(e.data); });
                        return _this;
                    }
                    TaskWatcher.prototype.updated = function (state) {
                        var isWatched = state.type === this.type;
                        var tasks = this.latestState.tasks;
                        if (!isWatched) {
                            if (tasks.has(state.taskId)) {
                                tasks = tasks.delete(state.taskId);
                                this.setState({ tasks: tasks });
                            }
                            return;
                        }
                        tasks = tasks.set(state.taskId, {
                            name: state.name,
                            message: state.message,
                            abort: state.abort
                        });
                        this.setState({ tasks: tasks });
                    };
                    TaskWatcher.prototype.started = function (task) {
                        this.setState({
                            tasks: this.latestState.tasks.set(task.id, { name: task.name, message: 'Running...' })
                        });
                    };
                    TaskWatcher.prototype.completed = function (taskId) {
                        if (!this.latestState.tasks.has(taskId))
                            return;
                        this.setState({
                            tasks: this.latestState.tasks.delete(taskId)
                        });
                    };
                    return TaskWatcher;
                }(Components.Component));
                Context.TaskWatcher = TaskWatcher;
            })(Context = Components.Context || (Components.Context = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Visualization;
            (function (Visualization) {
                "use strict";
                var HighlightInfo = /** @class */ (function (_super) {
                    __extends(HighlightInfo, _super);
                    function HighlightInfo(context) {
                        var _this = _super.call(this, context, { info: [] }) || this;
                        Bootstrap.Event.Interactivity.Highlight.getStream(_this.context).subscribe(function (e) { return _this.setState({ info: e.data }); });
                        return _this;
                    }
                    return HighlightInfo;
                }(Components.Component));
                Visualization.HighlightInfo = HighlightInfo;
            })(Visualization = Components.Visualization || (Components.Visualization = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Components;
        (function (Components) {
            var Visualization;
            (function (Visualization) {
                "use strict";
                var Vis = LiteMol.Visualization;
                var Viewport = /** @class */ (function (_super) {
                    __extends(Viewport, _super);
                    function Viewport(context) {
                        var _this = _super.call(this, context, Bootstrap.Utils.shallowClone(Vis.DefaultSceneOptions)) || this;
                        Bootstrap.Event.Common.LayoutChanged.getStream(_this.context).subscribe(function (e) {
                            if (_this._scene)
                                _this._scene.scene.resized();
                        });
                        Bootstrap.Command.Layout.SetViewportOptions.getStream(_this.context).subscribe(function (e) { return _this.setState(e.data); });
                        _this.state.throttle(1000 / 30).subscribe(function (s) {
                            _this.scene.scene.updateOptions(s);
                        });
                        return _this;
                    }
                    Object.defineProperty(Viewport.prototype, "scene", {
                        get: function () {
                            return this._scene;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Viewport.prototype.init = function (element) {
                        if (!LiteMol.Visualization.checkWebGL())
                            return false;
                        try {
                            this._scene = new Bootstrap.Visualization.SceneWrapper(element, this.context, this.latestState);
                            this.context.scene = this._scene;
                            return true;
                        }
                        catch (e) {
                            return false;
                        }
                    };
                    Viewport.prototype.destroy = function () {
                        if (this._scene) {
                            this._scene.destroy();
                            this._scene = null;
                        }
                    };
                    return Viewport;
                }(Components.Component));
                Visualization.Viewport = Viewport;
            })(Visualization = Components.Visualization || (Components.Visualization = {}));
        })(Components = Bootstrap.Components || (Bootstrap.Components = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var Settings = /** @class */ (function () {
            function Settings() {
                this.settings = LiteMol.Core.Utils.FastMap.create();
            }
            Settings.prototype.set = function (key, value) {
                this.settings.set(key, value);
            };
            Settings.prototype.get = function (key) {
                return this.settings.get(key);
            };
            return Settings;
        }());
        Bootstrap.Settings = Settings;
        var Context = /** @class */ (function () {
            function Context(plugin) {
                this.plugin = plugin;
                this.id = Bootstrap.Utils.generateUUID();
                this.dispatcher = new Bootstrap.Service.Dispatcher();
                this.logger = new Bootstrap.Service.Logger(this);
                this.performance = new LiteMol.Core.Utils.PerformanceMonitor();
                this.scene = void 0; // injected by the Viewport component.        
                this.tree = Bootstrap.Tree.create(this, Bootstrap.Entity.Root.create(Bootstrap.Entity.RootTransform, { label: 'Root Entity' }));
                this.currentEntity = void 0;
                this.transforms = new Bootstrap.TransformManager(this);
                this.entityCache = new Bootstrap.Entity.Cache(this);
                this.viewport = new Bootstrap.Components.Visualization.Viewport(this);
                this.highlight = new Bootstrap.Interactivity.HighlightManager(this);
                this.behaviours = new Bootstrap.Behaviour.Streams(this);
                this.settings = new Settings();
                Bootstrap.initEventsAndCommands(this);
            }
            Context.prototype.createLayout = function (targets, target) {
                this.layout = new Bootstrap.Components.Layout(this, targets, target);
            };
            Context.prototype.select = function (selector) {
                return Bootstrap.Tree.Selection.select(selector, this.tree);
            };
            return Context;
        }());
        Bootstrap.Context = Context;
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        var Plugin;
        (function (Plugin) {
            "use strict";
        })(Plugin = Bootstrap.Plugin || (Bootstrap.Plugin = {}));
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        function createMoleculeModelSelectInteraction(context, what) {
            if (!Bootstrap.Utils.Molecule.findModelOrSelection(what.entity)) {
                console.warn('Select: Trying to create a selection event on a non-molecule related entity, ignoring...');
                return;
            }
            var q = Bootstrap.Utils.Molecule.getModelAndIndicesFromQuery(what.entity, what.query);
            if (!q || !q.indices.length)
                return;
            Bootstrap.Event.Visual.VisualSelectElement.dispatch(context, Bootstrap.Interactivity.Info.selection(what.entity, q.indices));
        }
        function initEventsAndCommands(context) {
            Bootstrap.Command.Entity.SetCurrent.getStream(context).subscribe(function (e) { return Bootstrap.Entity.setCurrent(e.data); });
            Bootstrap.Command.Entity.SetVisibility.getStream(context).subscribe(function (e) { return Bootstrap.Entity.setVisibility(e.data.entity, e.data.visible); });
            Bootstrap.Command.Entity.ToggleExpanded.getStream(context).subscribe(function (e) { return Bootstrap.Entity.toggleExpanded(e.data); });
            Bootstrap.Command.Tree.RemoveNode.getStream(context).subscribe(function (e) { return context.select(e.data).forEach(function (n) { return Bootstrap.Tree.remove(n); }); });
            Bootstrap.Command.Tree.ApplyTransform.getStream(context).subscribe(function (e) { (e.data.isUpdate ? e.data.transform.update(context, e.data.node) : e.data.transform.apply(context, e.data.node)).run(); });
            Bootstrap.Event.Tree.NodeAdded.getStream(context).subscribe(function (e) {
                var vis = e.data.parent.state.visibility;
                var visible = vis !== 2 /* None */;
                Bootstrap.Entity.setVisibility(e.data, visible);
                if (Bootstrap.Entity.isClass(e.data, Bootstrap.Entity.BehaviourClass)) {
                    var b = e.data;
                    b.props.behaviour.register(b);
                }
            });
            Bootstrap.Event.Tree.NodeRemoved.getStream(context).subscribe(function (e) {
                Bootstrap.Entity.updateVisibilityState(e.data.parent);
                if (Bootstrap.Entity.isClass(e.data, Bootstrap.Entity.BehaviourClass)) {
                    var b = e.data;
                    b.props.behaviour.dispose();
                }
            });
            Bootstrap.Event.Visual.VisualHoverElement.getStream(context)
                .distinctUntilChanged(function (e) { return e.data; }, Bootstrap.Interactivity.interactivityInfoEqual)
                .map(function (e) { return Bootstrap.Interactivity.Molecule.transformInteraction(e.data); })
                .distinctUntilChanged(function (e) { return e; }, function (x, y) { return x === y; })
                .subscribe(function (info) { return Bootstrap.Event.Molecule.ModelHighlight.dispatch(context, info); });
            Bootstrap.Event.Visual.VisualSelectElement.getStream(context)
                .distinctUntilChanged(function (e) { return e.data; }, Bootstrap.Interactivity.interactivityInfoEqual)
                .map(function (e) { return Bootstrap.Interactivity.Molecule.transformInteraction(e.data); })
                .distinctUntilChanged(function (e) { return e; }, function (x, y) { return x === y; })
                .subscribe(function (info) { return Bootstrap.Event.Molecule.ModelSelect.dispatch(context, info); });
            Bootstrap.Command.Molecule.CreateSelectInteraction.getStream(context).subscribe(function (e) { return createMoleculeModelSelectInteraction(context, e.data); });
        }
        Bootstrap.initEventsAndCommands = initEventsAndCommands;
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Bootstrap;
    (function (Bootstrap) {
        "use strict";
        var TransformManager = /** @class */ (function () {
            function TransformManager(context) {
                var _this = this;
                this.context = context;
                this.controllerCache = LiteMol.Core.Utils.FastMap.create();
                this.state = LiteMol.Core.Utils.FastMap.create();
                this.byId = LiteMol.Core.Utils.FastMap.create();
                this.bySourceType = LiteMol.Core.Utils.FastMap.create();
                this.byTargetType = LiteMol.Core.Utils.FastMap.create();
                Bootstrap.Event.Tree.NodeRemoved.getStream(context).subscribe(function (e) {
                    _this.controllerCache.delete(e.data.id);
                    _this.state.delete(e.data.id);
                });
            }
            TransformManager.prototype.addType = function (e, t, to) {
                var xs = to.get(e.id);
                if (!xs)
                    to.set(e.id, [t]);
                else
                    xs.push(t);
            };
            TransformManager.prototype.getController = function (t, e) {
                if (!e) {
                    console.warn("Trying to get controller for undefined entity.");
                    return void 0;
                }
                if (!this.byId.get(t.info.id)) {
                    console.warn("Trying to get controller for unregistered transform (" + t.info.id + ").");
                    return void 0;
                }
                var cs = this.controllerCache.get(e.id);
                if (!cs) {
                    cs = LiteMol.Core.Utils.FastMap.create();
                    this.controllerCache.set(e.id, cs);
                }
                var c = cs.get(t.info.id);
                if (c)
                    return c;
                var p = t.info.customController;
                if (p)
                    c = p(this.context, t, e);
                else
                    c = new Bootstrap.Components.Transform.Controller(this.context, t, e);
                var info = this.context.plugin && this.context.plugin.getTransformerInfo(t);
                if (info && info.initiallyCollapsed) {
                    if (!this.hasPersistentState(t, e, 'isExpanded'))
                        this.setPersistentState(t, e, 'isExpanded', false);
                }
                else {
                    if (!this.hasPersistentState(t, e, 'isExpanded'))
                        this.setPersistentState(t, e, 'isExpanded', true);
                }
                if (e.transform.transformer === t) {
                    c.setParams(e.transform.params);
                }
                cs.set(t.info.id, c);
                return c;
            };
            TransformManager.prototype.getBySourceType = function (t) {
                return this.bySourceType.get(t.id) || [];
            };
            TransformManager.prototype.getByTargetType = function (t) {
                return this.byTargetType.get(t.id) || [];
            };
            TransformManager.prototype.add = function (t) {
                if (this.byId.has(t.info.id)) {
                    throw "Transformer with id '" + t.info.id + "' is has already been added. Pick another id.";
                }
                this.byId.set(t.info.id, t);
                for (var _i = 0, _a = t.info.from; _i < _a.length; _i++) {
                    var x = _a[_i];
                    this.addType(x, t, this.bySourceType);
                }
                for (var _b = 0, _c = t.info.to; _b < _c.length; _b++) {
                    var x = _c[_b];
                    this.addType(x, t, this.byTargetType);
                }
            };
            TransformManager.prototype.hasPersistentState = function (t, e, prop) {
                var se = this.state.get(e.id);
                if (!se)
                    return false;
                var ps = se.get(t.info.id);
                if (!ps || !ps.has(prop))
                    return false;
                return true;
            };
            TransformManager.prototype.getPersistentState = function (t, e, prop, defaultValue) {
                var se = this.state.get(e.id);
                if (!se)
                    return defaultValue;
                var ps = se.get(t.info.id);
                if (!ps || !ps.has(prop))
                    return defaultValue;
                return ps.get(prop);
            };
            /**
             * returns whether the value changed or not
             */
            TransformManager.prototype.setPersistentState = function (t, e, prop, value) {
                var se = this.state.get(e.id);
                if (!se) {
                    se = LiteMol.Core.Utils.FastMap.create();
                    this.state.set(e.id, se);
                }
                var ps = se.get(t.info.id);
                if (!ps) {
                    ps = LiteMol.Core.Utils.FastMap.create();
                    se.set(t.info.id, ps);
                }
                var old = ps.get(prop);
                ps.set(prop, value);
                return old !== value;
            };
            return TransformManager;
        }());
        Bootstrap.TransformManager = TransformManager;
    })(Bootstrap = LiteMol.Bootstrap || (LiteMol.Bootstrap = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        Plugin.VERSION = { number: "1.3.4", date: "September 7 2017" };
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        "use strict";
        Plugin.React = __LiteMolReact;
        Plugin.ReactDOM = __LiteMolReactDOM;
        var Controls;
        (function (Controls) {
            //export const ColorPickerHelper: __LiteMolColorPicker.ColorPicker = <any>__LiteMolColorPicker.ColorPicker;
            //export const AlphaPickerHelper: __LiteMolColorPicker.AlphaPicker = <any>(__LiteMolColorPicker as any).AlphaPicker;
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
        Controls.ChromePickerHelper = __LiteMolColorPicker.ChromePicker;
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            var shallowEqual = LiteMol.Bootstrap.Utils.shallowEqual;
            var Pure = /** @class */ (function (_super) {
                __extends(Pure, _super);
                function Pure() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Pure.prototype.shouldComponentUpdate = function (nextProps, nextState) {
                    return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
                };
                return Pure;
            }(Plugin.React.Component));
            Controls.Pure = Pure;
            var Button = /** @class */ (function (_super) {
                __extends(Button, _super);
                function Button() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Button.prototype.render = function () {
                    var props = this.props;
                    var className = 'lm-btn';
                    if (props.size && props.size !== 'normal')
                        className += ' lm-btn-' + props.size;
                    if (props.asBlock)
                        className += ' lm-btn-block';
                    if (props.disabled)
                        className += ' lm-btn-' + (props.disabledStyle || props.style || 'default');
                    else if (props.active)
                        className += ' lm-btn-' + (props.activeStyle || props.style || 'default');
                    else
                        className += ' lm-btn-' + (props.style || 'default');
                    if (props.customClass)
                        className += ' ' + props.customClass;
                    var icon = void 0;
                    if (props.icon) {
                        if (props.active && props.activeIcon)
                            icon = Plugin.React.createElement("span", { className: "lm-icon lm-icon-" + props.activeIcon });
                        else
                            icon = Plugin.React.createElement("span", { className: "lm-icon lm-icon-" + props.icon });
                    }
                    //onTouchEnd={(e) => { (e.target as HTMLElement).blur() } }
                    return Plugin.React.createElement("button", { title: props.title, className: className, style: props.customStyle, disabled: props.disabled, onClick: function (e) { props.onClick.call(null, e); e.target.blur(); } },
                        icon,
                        props.children);
                };
                return Button;
            }(Pure));
            Controls.Button = Button;
            Controls.TextBox = function (props) { return Plugin.React.createElement("input", { type: 'text', className: 'lm-form-control', placeholder: props.placeholder, value: props.value, defaultValue: props.defaultValue, onBlur: function (e) { if (props.onBlur)
                    props.onBlur.call(null, e); }, onChange: function (e) { return props.onChange.call(null, e.target.value); }, onKeyPress: props.onKeyPress }); };
            function isEnter(e) {
                if ((e.keyCode === 13 || e.charCode === 13)) {
                    return true;
                }
                return false;
            }
            Controls.isEnter = isEnter;
            function TextBoxGroup(props) {
                return Plugin.React.createElement("div", { className: 'lm-control-row lm-options-group', title: props.title },
                    Plugin.React.createElement("span", null, props.label),
                    Plugin.React.createElement("div", null,
                        Plugin.React.createElement(Controls.TextBox, { placeholder: props.placeholder, onChange: props.onChange, value: props.value, onKeyPress: function (e) {
                                if (isEnter(e) && props.onEnter)
                                    props.onEnter.call(null, e);
                            } })));
            }
            Controls.TextBoxGroup = TextBoxGroup;
            Controls.CommitButton = function (props) { return Plugin.React.createElement("div", { style: { marginTop: '1px' } },
                Plugin.React.createElement("button", { onClick: function (e) { props.action(); e.target.blur(); }, className: 'lm-btn lm-btn-block lm-btn-commit lm-btn-commit-' + (props.isOn ? 'on' : 'off'), disabled: !props.isOn, title: props.title },
                    Plugin.React.createElement("span", { className: "lm-icon lm-icon-" + (props.isOn ? 'ok' : 'cross') }),
                    props.isOn ? Plugin.React.createElement("b", null, props.on) : (props.off ? props.off : props.on))); };
            // <Controls.Button onClick={() => props.action() }
            //         style={props.isOn ? 'success' : 'default' } asBlock={true} disabled={!props.isOn} icon={props.isOn ? 'ok' : 'cross'} 
            //             customClass='lm-commit-button'>
            //             {props.isOn ? props.on : (props.off ? props.off : props.on) }
            //         </Controls.Button>  
            Controls.Toggle = function (props) { return Plugin.React.createElement("div", { className: 'lm-control-row lm-toggle-button', title: props.title },
                Plugin.React.createElement("span", null, props.label),
                Plugin.React.createElement("div", null,
                    Plugin.React.createElement("button", { onClick: function (e) { props.onChange.call(null, !props.value); e.target.blur(); } },
                        Plugin.React.createElement("span", { className: "lm-icon lm-icon-" + (props.value ? 'ok' : 'off') }),
                        " ",
                        props.value ? 'On' : 'Off'))); };
            Controls.ControlGroupExpander = function (props) {
                return Plugin.React.createElement(Controls.Button, { style: 'link', title: (props.isExpanded ? 'Less' : 'More') + " options", onClick: function () { return props.onChange.call(null, !props.isExpanded); }, icon: props.isExpanded ? 'minus' : 'plus', customClass: 'lm-conrol-group-expander' });
            };
            Controls.RowText = function (props) { return Plugin.React.createElement("div", { className: 'lm-control-row lm-row-text', title: props.title },
                Plugin.React.createElement("span", null, props.label),
                Plugin.React.createElement("div", null, props.value)); };
            Controls.HelpBox = function (props) { return Plugin.React.createElement("div", { className: 'lm-help-row' },
                Plugin.React.createElement("span", null, props.title),
                Plugin.React.createElement("div", null, props.content)); };
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            var OptionsBox = /** @class */ (function (_super) {
                __extends(OptionsBox, _super);
                function OptionsBox() {
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this.current = void 0;
                    return _this;
                }
                OptionsBox.prototype.get = function (i) {
                    var opts = this.props.options;
                    if (typeof opts.get !== 'undefined')
                        return opts.get(i);
                    return opts[i];
                };
                OptionsBox.prototype.render = function () {
                    var _this = this;
                    var cap = this.props.caption;
                    var idx = this.props.options.indexOf(this.props.current);
                    if (idx < 0)
                        idx = 0;
                    return Plugin.React.createElement("select", { title: this.props.title, value: idx.toString(), className: 'lm-form-control', onChange: function (e) {
                            _this.current = _this.get(+e.target.value);
                            _this.props.onChange(_this.current);
                        } }, this.props.options.map(function (o, i) {
                        return Plugin.React.createElement("option", { key: i, value: "" + i }, cap(o));
                    }));
                };
                return OptionsBox;
            }(Plugin.React.Component));
            Controls.OptionsBox = OptionsBox;
            function OptionsGroup(props) {
                var caption = props.caption ? props.caption : function (o) { return o; };
                return Plugin.React.createElement("div", { className: 'lm-control-row lm-options-group', title: props.title },
                    Plugin.React.createElement("span", null, props.label),
                    Plugin.React.createElement("div", null,
                        Plugin.React.createElement(Controls.OptionsBox, { options: props.options, caption: caption, current: props.current, onChange: props.onChange })));
            }
            Controls.OptionsGroup = OptionsGroup;
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            var Panel = /** @class */ (function (_super) {
                __extends(Panel, _super);
                function Panel() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Panel.prototype.header = function () {
                    var _this = this;
                    var exp = this.props.isExpanded;
                    var title = this.props.title ? this.props.title : this.props.header;
                    var icon = exp ? 'collapse' : 'expand';
                    var desc = Plugin.React.createElement("div", { className: "lm-panel-description lm-panel-description-" + (this.props.topRightAction ? 'with-action' : 'standalone'), onClick: function () { return _this.props.onExpand.call(null, !_this.props.isExpanded); } },
                        Plugin.React.createElement("span", { className: 'lm-icon lm-icon-info' }),
                        Plugin.React.createElement("div", { className: 'lm-panel-description-content' },
                            Plugin.React.createElement("span", { className: 'lm-icon lm-icon-info' }),
                            this.props.description));
                    return Plugin.React.createElement("div", { className: 'lm-panel-header' },
                        desc,
                        this.props.topRightAction,
                        Plugin.React.createElement("div", { className: 'lm-panel-expander-wrapper' },
                            Plugin.React.createElement(Controls.Button, { title: title, onClick: function () { return _this.props.onExpand.call(null, !_this.props.isExpanded); }, icon: icon, customClass: 'lm-panel-expander', style: 'link' },
                                this.props.badge,
                                this.props.header)));
                };
                Panel.prototype.render = function () {
                    var cls = 'lm-panel' + (this.props.className ? ' ' + this.props.className : '') + (this.props.isExpanded ? ' lm-panel-expanded' : ' lm-panel-collapsed');
                    return Plugin.React.createElement("div", { className: cls },
                        this.header(),
                        Plugin.React.createElement("div", { className: 'lm-panel-body', style: { display: this.props.isExpanded ? 'block' : 'none' } }, this.props.children));
                };
                return Panel;
            }(Plugin.React.Component));
            Controls.Panel = Panel;
            Controls.ExpandableGroup = function (props) {
                return Plugin.React.createElement("div", { className: 'lm-control-group' },
                    props.select,
                    props.colorStripe ? Plugin.React.createElement("div", { className: 'lm-expandable-group-color-stripe', style: { backgroundColor: "rgb(" + ((255 * props.colorStripe.r) | 0) + ", " + ((255 * props.colorStripe.g) | 0) + ", " + ((255 * props.colorStripe.b) | 0) + ")" } }) : void 0,
                    props.options.length > 0 ? props.expander : void 0,
                    props.options.length > 0 ? Plugin.React.createElement("div", { style: { display: props.isExpanded ? 'block' : 'none' }, className: 'lm-control-subgroup' }, props.options) : void 0);
            };
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            var Slider = /** @class */ (function (_super) {
                __extends(Slider, _super);
                function Slider() {
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this.state = { value: '0' };
                    _this.firedValue = NaN;
                    return _this;
                }
                Slider.prototype.componentWillMount = function () {
                    this.setState({ value: '' + this.props.value });
                };
                Slider.prototype.componentWillReceiveProps = function (nextProps) {
                    this.setState({ value: '' + nextProps.value });
                };
                Slider.prototype.updateValue = function (s) {
                    var v = +s;
                    if (v < this.props.min) {
                        v = this.props.min;
                        s = '' + v;
                    }
                    else if (v > this.props.max) {
                        v = this.props.max;
                        s = '' + v;
                    }
                    this.setState({ value: s });
                };
                Slider.prototype.fire = function () {
                    var v = +this.state.value;
                    if (isNaN(v)) {
                        v = this.props.value;
                    }
                    if (v !== this.props.value) {
                        if (this.firedValue !== v) {
                            this.firedValue = v;
                            this.props.onChange.call(null, v);
                        }
                    }
                };
                Slider.prototype.render = function () {
                    var _this = this;
                    var step = this.props.step;
                    if (step === void 0)
                        step = 1;
                    return Plugin.React.createElement("div", { className: 'lm-control-row lm-slider', title: this.props.title },
                        Plugin.React.createElement("span", null, this.props.label),
                        Plugin.React.createElement("div", null,
                            Plugin.React.createElement("div", null,
                                Plugin.React.createElement("div", null,
                                    Plugin.React.createElement(SliderBase, { min: this.props.min, max: this.props.max, step: step, value: +this.state.value, onChange: function (v) { return _this.setState({ value: '' + v }); }, onAfterChange: function (v) { return _this.fire(); } }))),
                            Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Controls.TextBox, { value: this.state.value, onChange: function (v) { return _this.updateValue(v); }, onBlur: function () { return _this.fire(); }, onKeyPress: function (e) {
                                        if (Controls.isEnter(e))
                                            _this.fire();
                                    } }))));
                };
                return Slider;
            }(Plugin.React.Component));
            Controls.Slider = Slider;
            /**
             * The following code was adapted from react-components/slider library.
             *
             * The MIT License (MIT)
             * Copyright (c) 2015-present Alipay.com, https://www.alipay.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 classNames(_classes) {
                var classes = [];
                var hasOwn = {}.hasOwnProperty;
                for (var i = 0; i < arguments.length; i++) {
                    var arg = arguments[i];
                    if (!arg)
                        continue;
                    var argType = typeof arg;
                    if (argType === 'string' || argType === 'number') {
                        classes.push(arg);
                    }
                    else if (Array.isArray(arg)) {
                        classes.push(classNames.apply(null, arg));
                    }
                    else if (argType === 'object') {
                        for (var key in arg) {
                            if (hasOwn.call(arg, key) && arg[key]) {
                                classes.push(key);
                            }
                        }
                    }
                }
                return classes.join(' ');
            }
            function noop() {
            }
            function isNotTouchEvent(e) {
                return e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0);
            }
            function getTouchPosition(vertical, e) {
                return vertical ? e.touches[0].clientY : e.touches[0].pageX;
            }
            function getMousePosition(vertical, e) {
                return vertical ? e.clientY : e.pageX;
            }
            function getHandleCenterPosition(vertical, handle) {
                var coords = handle.getBoundingClientRect();
                return vertical ?
                    coords.top + (coords.height * 0.5) :
                    coords.left + (coords.width * 0.5);
            }
            function pauseEvent(e) {
                e.stopPropagation();
                e.preventDefault();
            }
            var Handle = /** @class */ (function (_super) {
                __extends(Handle, _super);
                function Handle() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Handle.prototype.render = function () {
                    var _a = this.props, className = _a.className, tipFormatter = _a.tipFormatter, vertical = _a.vertical, offset = _a.offset, value = _a.value, index = _a.index;
                    var style = vertical ? { bottom: offset + "%" } : { left: offset + "%" };
                    return (Plugin.React.createElement("div", { className: className, style: style, title: tipFormatter(value, index) }));
                };
                return Handle;
            }(Plugin.React.Component));
            Controls.Handle = Handle;
            var SliderBase = /** @class */ (function (_super) {
                __extends(SliderBase, _super);
                function SliderBase(props) {
                    var _this = _super.call(this, props) || this;
                    _this.sliderElement = void 0;
                    _this.handleElements = [];
                    _this.dragOffset = 0;
                    _this.startPosition = 0;
                    _this.startValue = 0;
                    _this._getPointsCache = void 0;
                    _this.eventHandlers = {
                        'touchmove': function (e) { return _this.onTouchMove(e); },
                        'touchend': function (e) { return _this.end('touch'); },
                        'mousemove': function (e) { return _this.onMouseMove(e); },
                        'mouseup': function (e) { return _this.end('mouse'); },
                    };
                    var range = props.range, min = props.min, max = props.max;
                    var initialValue = range ? Array.apply(null, Array(+range + 1)).map(function () { return min; }) : min;
                    var defaultValue = ('defaultValue' in props ? props.defaultValue : initialValue);
                    var value = (props.value !== undefined ? props.value : defaultValue);
                    var bounds = (range ? value : [min, value]).map(function (v) { return _this.trimAlignValue(v); });
                    var recent;
                    if (range && bounds[0] === bounds[bounds.length - 1] && bounds[0] === max) {
                        recent = 0;
                    }
                    else {
                        recent = bounds.length - 1;
                    }
                    _this.state = {
                        handle: null,
                        recent: recent,
                        bounds: bounds,
                    };
                    return _this;
                }
                SliderBase.prototype.componentWillReceiveProps = function (nextProps) {
                    var _this = this;
                    if (!('value' in nextProps || 'min' in nextProps || 'max' in nextProps))
                        return;
                    var bounds = this.state.bounds;
                    if (nextProps.range) {
                        var value = nextProps.value || bounds;
                        var nextBounds = value.map(function (v) { return _this.trimAlignValue(v, nextProps); });
                        if (nextBounds.every(function (v, i) { return v === bounds[i]; }))
                            return;
                        this.setState({ bounds: nextBounds });
                        if (bounds.some(function (v) { return _this.isValueOutOfBounds(v, nextProps); })) {
                            this.props.onChange(nextBounds);
                        }
                    }
                    else {
                        var value = nextProps.value !== undefined ? nextProps.value : bounds[1];
                        var nextValue = this.trimAlignValue(value, nextProps);
                        if (nextValue === bounds[1] && bounds[0] === nextProps.min)
                            return;
                        this.setState({ bounds: [nextProps.min, nextValue] });
                        if (this.isValueOutOfBounds(bounds[1], nextProps)) {
                            this.props.onChange(nextValue);
                        }
                    }
                };
                SliderBase.prototype.onChange = function (state) {
                    var props = this.props;
                    var isNotControlled = !('value' in props);
                    if (isNotControlled) {
                        this.setState(state);
                    }
                    else if (state.handle !== undefined) {
                        this.setState({ handle: state.handle });
                    }
                    var data = __assign({}, this.state, state);
                    var changedValue = props.range ? data.bounds : data.bounds[1];
                    props.onChange(changedValue);
                };
                SliderBase.prototype.onMouseDown = function (e) {
                    if (e.button !== 0) {
                        return;
                    }
                    var position = getMousePosition(this.props.vertical, e);
                    if (!this.isEventFromHandle(e)) {
                        this.dragOffset = 0;
                    }
                    else {
                        var handlePosition = getHandleCenterPosition(this.props.vertical, e.target);
                        this.dragOffset = position - handlePosition;
                        position = handlePosition;
                    }
                    this.onStart(position);
                    this.addDocumentEvents('mouse');
                    pauseEvent(e);
                };
                SliderBase.prototype.onMouseMove = function (e) {
                    var position = getMousePosition(this.props.vertical, e);
                    this.onMove(e, position - this.dragOffset);
                };
                SliderBase.prototype.onMove = function (e, position) {
                    pauseEvent(e);
                    var props = this.props;
                    var state = this.state;
                    var diffPosition = position - this.startPosition;
                    diffPosition = this.props.vertical ? -diffPosition : diffPosition;
                    var diffValue = diffPosition / this.getSliderLength() * (props.max - props.min);
                    var value = this.trimAlignValue(this.startValue + diffValue);
                    var oldValue = state.bounds[state.handle];
                    if (value === oldValue)
                        return;
                    var nextBounds = state.bounds.slice();
                    nextBounds[state.handle] = value;
                    var nextHandle = state.handle;
                    if (props.pushable !== false) {
                        var originalValue = state.bounds[nextHandle];
                        this.pushSurroundingHandles(nextBounds, nextHandle, originalValue);
                    }
                    else if (props.allowCross) {
                        nextBounds.sort(function (a, b) { return a - b; });
                        nextHandle = nextBounds.indexOf(value);
                    }
                    this.onChange({
                        handle: nextHandle,
                        bounds: nextBounds,
                    });
                };
                SliderBase.prototype.onStart = function (position) {
                    var props = this.props;
                    props.onBeforeChange(this.getValue());
                    var value = this.calcValueByPos(position);
                    this.startValue = value;
                    this.startPosition = position;
                    var state = this.state;
                    var bounds = state.bounds;
                    var valueNeedChanging = 1;
                    if (this.props.range) {
                        var closestBound = 0;
                        for (var i = 1; i < bounds.length - 1; ++i) {
                            if (value > bounds[i]) {
                                closestBound = i;
                            }
                        }
                        if (Math.abs(bounds[closestBound + 1] - value) < Math.abs(bounds[closestBound] - value)) {
                            closestBound = closestBound + 1;
                        }
                        valueNeedChanging = closestBound;
                        var isAtTheSamePoint = (bounds[closestBound + 1] === bounds[closestBound]);
                        if (isAtTheSamePoint) {
                            valueNeedChanging = state.recent;
                        }
                        if (isAtTheSamePoint && (value !== bounds[closestBound + 1])) {
                            valueNeedChanging = value < bounds[closestBound + 1] ? closestBound : closestBound + 1;
                        }
                    }
                    this.setState({
                        handle: valueNeedChanging,
                        recent: valueNeedChanging,
                    });
                    var oldValue = state.bounds[valueNeedChanging];
                    if (value === oldValue)
                        return;
                    var nextBounds = state.bounds.slice();
                    nextBounds[valueNeedChanging] = value;
                    this.onChange({ bounds: nextBounds });
                };
                SliderBase.prototype.onTouchMove = function (e) {
                    if (isNotTouchEvent(e)) {
                        this.end('touch');
                        return;
                    }
                    var position = getTouchPosition(this.props.vertical, e);
                    this.onMove(e, position - this.dragOffset);
                };
                SliderBase.prototype.onTouchStart = function (e) {
                    if (isNotTouchEvent(e))
                        return;
                    var position = getTouchPosition(this.props.vertical, e);
                    if (!this.isEventFromHandle(e)) {
                        this.dragOffset = 0;
                    }
                    else {
                        var handlePosition = getHandleCenterPosition(this.props.vertical, e.target);
                        this.dragOffset = position - handlePosition;
                        position = handlePosition;
                    }
                    this.onStart(position);
                    this.addDocumentEvents('touch');
                    pauseEvent(e);
                };
                /**
                 * Returns an array of possible slider points, taking into account both
                 * `marks` and `step`. The result is cached.
                 */
                SliderBase.prototype.getPoints = function () {
                    var _a = this.props, marks = _a.marks, step = _a.step, min = _a.min, max = _a.max;
                    var cache = this._getPointsCache;
                    if (!cache || cache.marks !== marks || cache.step !== step) {
                        var pointsObject = __assign({}, marks);
                        if (step !== null) {
                            for (var point = min; point <= max; point += step) {
                                pointsObject[point] = point;
                            }
                        }
                        var points = Object.keys(pointsObject).map(parseFloat);
                        points.sort(function (a, b) { return a - b; });
                        this._getPointsCache = { marks: marks, step: step, points: points };
                    }
                    return this._getPointsCache.points;
                };
                SliderBase.prototype.getPrecision = function (step) {
                    var stepString = step.toString();
                    var precision = 0;
                    if (stepString.indexOf('.') >= 0) {
                        precision = stepString.length - stepString.indexOf('.') - 1;
                    }
                    return precision;
                };
                SliderBase.prototype.getSliderLength = function () {
                    var slider = this.sliderElement;
                    if (!slider) {
                        return 0;
                    }
                    return this.props.vertical ? slider.clientHeight : slider.clientWidth;
                };
                SliderBase.prototype.getSliderStart = function () {
                    var slider = this.sliderElement;
                    var rect = slider.getBoundingClientRect();
                    return this.props.vertical ? rect.top : rect.left;
                };
                SliderBase.prototype.getValue = function () {
                    var bounds = this.state.bounds;
                    return (this.props.range ? bounds : bounds[1]);
                };
                SliderBase.prototype.addDocumentEvents = function (type) {
                    if (type === 'touch') {
                        document.addEventListener('touchmove', this.eventHandlers.touchmove);
                        document.addEventListener('touchend', this.eventHandlers.touchend);
                    }
                    else if (type === 'mouse') {
                        document.addEventListener('mousemove', this.eventHandlers.mousemove);
                        document.addEventListener('mouseup', this.eventHandlers.mouseup);
                    }
                };
                SliderBase.prototype.calcOffset = function (value) {
                    var _a = this.props, min = _a.min, max = _a.max;
                    var ratio = (value - min) / (max - min);
                    return ratio * 100;
                };
                SliderBase.prototype.calcValue = function (offset) {
                    var _a = this.props, vertical = _a.vertical, min = _a.min, max = _a.max;
                    var ratio = Math.abs(offset / this.getSliderLength());
                    var value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min;
                    return value;
                };
                SliderBase.prototype.calcValueByPos = function (position) {
                    var pixelOffset = position - this.getSliderStart();
                    var nextValue = this.trimAlignValue(this.calcValue(pixelOffset));
                    return nextValue;
                };
                SliderBase.prototype.end = function (type) {
                    this.removeEvents(type);
                    this.props.onAfterChange(this.getValue());
                    this.setState({ handle: null });
                };
                SliderBase.prototype.isEventFromHandle = function (e) {
                    for (var _i = 0, _a = this.handleElements; _i < _a.length; _i++) {
                        var h = _a[_i];
                        if (h === e.target)
                            return true;
                    }
                    return false;
                    // return this.state.bounds.some((x, i) => e.target 
                    // (
                    //     //this.handleElements[i] && e.target === ReactDOM.findDOMNode(this.handleElements[i])
                    // ));
                };
                SliderBase.prototype.isValueOutOfBounds = function (value, props) {
                    return value < props.min || value > props.max;
                };
                SliderBase.prototype.pushHandle = function (bounds, handle, direction, amount) {
                    var originalValue = bounds[handle];
                    var currentValue = bounds[handle];
                    while (direction * (currentValue - originalValue) < amount) {
                        if (!this.pushHandleOnePoint(bounds, handle, direction)) {
                            // can't push handle enough to create the needed `amount` gap, so we
                            // revert its position to the original value
                            bounds[handle] = originalValue;
                            return false;
                        }
                        currentValue = bounds[handle];
                    }
                    // the handle was pushed enough to create the needed `amount` gap
                    return true;
                };
                SliderBase.prototype.pushHandleOnePoint = function (bounds, handle, direction) {
                    var points = this.getPoints();
                    var pointIndex = points.indexOf(bounds[handle]);
                    var nextPointIndex = pointIndex + direction;
                    if (nextPointIndex >= points.length || nextPointIndex < 0) {
                        // reached the minimum or maximum available point, can't push anymore
                        return false;
                    }
                    var nextHandle = handle + direction;
                    var nextValue = points[nextPointIndex];
                    var threshold = this.props.pushable;
                    var diffToNext = direction * (bounds[nextHandle] - nextValue);
                    if (!this.pushHandle(bounds, nextHandle, direction, +threshold - diffToNext)) {
                        // couldn't push next handle, so we won't push this one either
                        return false;
                    }
                    // push the handle
                    bounds[handle] = nextValue;
                    return true;
                };
                SliderBase.prototype.pushSurroundingHandles = function (bounds, handle, originalValue) {
                    var threshold = this.props.pushable;
                    var value = bounds[handle];
                    var direction = 0;
                    if (bounds[handle + 1] - value < threshold) {
                        direction = +1;
                    }
                    else if (value - bounds[handle - 1] < threshold) {
                        direction = -1;
                    }
                    if (direction === 0) {
                        return;
                    }
                    var nextHandle = handle + direction;
                    var diffToNext = direction * (bounds[nextHandle] - value);
                    if (!this.pushHandle(bounds, nextHandle, direction, +threshold - diffToNext)) {
                        // revert to original value if pushing is impossible
                        bounds[handle] = originalValue;
                    }
                };
                SliderBase.prototype.removeEvents = function (type) {
                    if (type === 'touch') {
                        document.removeEventListener('touchmove', this.eventHandlers.touchmove);
                        document.removeEventListener('touchend', this.eventHandlers.touchend);
                    }
                    else if (type === 'mouse') {
                        document.removeEventListener('mousemove', this.eventHandlers.mousemove);
                        document.removeEventListener('mouseup', this.eventHandlers.mouseup);
                    }
                };
                SliderBase.prototype.trimAlignValue = function (v, nextProps) {
                    var _a = (this.state || {}), handle = _a.handle, bounds = _a.bounds;
                    var _b = __assign({}, this.props, (nextProps || {})), marks = _b.marks, step = _b.step, min = _b.min, max = _b.max, allowCross = _b.allowCross;
                    var val = v;
                    if (val <= min) {
                        val = min;
                    }
                    if (val >= max) {
                        val = max;
                    }
                    /* eslint-disable eqeqeq */
                    if (!allowCross && handle != null && handle > 0 && val <= bounds[handle - 1]) {
                        val = bounds[handle - 1];
                    }
                    if (!allowCross && handle != null && handle < bounds.length - 1 && val >= bounds[handle + 1]) {
                        val = bounds[handle + 1];
                    }
                    /* eslint-enable eqeqeq */
                    var points = Object.keys(marks).map(parseFloat);
                    if (step !== null) {
                        var closestStep = (Math.round((val - min) / step) * step) + min;
                        points.push(closestStep);
                    }
                    var diffs = points.map(function (point) { return Math.abs(val - point); });
                    var closestPoint = points[diffs.indexOf(Math.min.apply(Math, diffs))];
                    return step !== null ? parseFloat(closestPoint.toFixed(this.getPrecision(step))) : closestPoint;
                };
                SliderBase.prototype.render = function () {
                    var _this = this;
                    var _a;
                    var _b = this.state, handle = _b.handle, bounds = _b.bounds;
                    var _c = this.props, className = _c.className, prefixCls = _c.prefixCls, disabled = _c.disabled, vertical = _c.vertical, dots = _c.dots, included = _c.included, range = _c.range, step = _c.step, marks = _c.marks, max = _c.max, min = _c.min, tipFormatter = _c.tipFormatter, children = _c.children;
                    var customHandle = this.props.handle;
                    var offsets = bounds.map(function (v) { return _this.calcOffset(v); });
                    var handleClassName = prefixCls + "-handle";
                    var handlesClassNames = bounds.map(function (v, i) {
                        var _a;
                        return classNames((_a = {},
                            _a[handleClassName] = true,
                            _a[handleClassName + "-" + (i + 1)] = true,
                            _a[handleClassName + "-lower"] = i === 0,
                            _a[handleClassName + "-upper"] = i === bounds.length - 1,
                            _a));
                    });
                    var isNoTip = (step === null) || (tipFormatter === null);
                    var commonHandleProps = {
                        prefixCls: prefixCls,
                        noTip: isNoTip,
                        tipFormatter: tipFormatter,
                        vertical: vertical,
                    };
                    this.handleElements = [];
                    var handles = bounds.map(function (v, i) { return Plugin.React.cloneElement(customHandle, __assign({}, commonHandleProps, { className: handlesClassNames[i], value: v, offset: offsets[i], dragging: handle === i, index: i, key: i, ref: function (h) { return _this.handleElements.push(h); } //`handle-${i}`,
                     })); });
                    if (!range) {
                        handles.shift();
                    }
                    var isIncluded = included || range;
                    var tracks = [];
                    // for (let i = 1; i < bounds.length; ++i) {
                    //     const trackClassName = classNames({
                    //         [`${prefixCls}-track`]: true,
                    //         [`${prefixCls}-track-${i}`]: true,
                    //     });
                    //     tracks.push(
                    //         <Track className={trackClassName} vertical={vertical} included={isIncluded}
                    //             offset={offsets[i - 1]} length={offsets[i] - offsets[i - 1]} key={i}
                    //             />
                    //     );
                    // }
                    var sliderClassName = classNames((_a = {},
                        _a[prefixCls] = true,
                        _a[prefixCls + "-with-marks"] = Object.keys(marks).length,
                        _a[prefixCls + "-disabled"] = disabled,
                        _a[prefixCls + "-vertical"] = this.props.vertical,
                        _a[className] = !!className,
                        _a));
                    return (Plugin.React.createElement("div", { ref: function (e) { return _this.sliderElement = e; }, className: sliderClassName, onTouchStart: disabled ? noop : this.onTouchStart.bind(this), onMouseDown: disabled ? noop : this.onMouseDown.bind(this) },
                        Plugin.React.createElement("div", { className: prefixCls + "-rail" }),
                        tracks,
                        Plugin.React.createElement(Steps, { prefixCls: prefixCls, vertical: vertical, marks: marks, dots: dots, step: step, included: isIncluded, lowerBound: bounds[0], upperBound: bounds[bounds.length - 1], max: max, min: min }),
                        handles,
                        Plugin.React.createElement(Marks, { className: prefixCls + "-mark", vertical: vertical, marks: marks, included: isIncluded, lowerBound: bounds[0], upperBound: bounds[bounds.length - 1], max: max, min: min }),
                        children));
                };
                SliderBase.defaultProps = {
                    prefixCls: 'lm-slider-base',
                    className: '',
                    min: 0,
                    max: 100,
                    step: 1,
                    marks: {},
                    handle: Plugin.React.createElement(Handle, { className: '', vertical: false, offset: 0, tipFormatter: function (v) { return v; }, value: 0, index: 0 }),
                    onBeforeChange: noop,
                    onChange: noop,
                    onAfterChange: noop,
                    tipFormatter: function (value, index) { return value; },
                    included: true,
                    disabled: false,
                    dots: false,
                    range: false,
                    vertical: false,
                    allowCross: true,
                    pushable: false,
                };
                return SliderBase;
            }(Plugin.React.Component));
            Controls.SliderBase = SliderBase;
            var Marks = function (_a) {
                var className = _a.className, vertical = _a.vertical, marks = _a.marks, included = _a.included, upperBound = _a.upperBound, lowerBound = _a.lowerBound, max = _a.max, min = _a.min;
                var marksKeys = Object.keys(marks);
                var marksCount = marksKeys.length;
                var unit = 100 / (marksCount - 1);
                var markWidth = unit * 0.9;
                var range = max - min;
                var elements = marksKeys.map(parseFloat).sort(function (a, b) { return a - b; }).map(function (point) {
                    var _a;
                    var isActived = (!included && point === upperBound) ||
                        (included && point <= upperBound && point >= lowerBound);
                    var markClassName = classNames((_a = {},
                        _a[className + "-text"] = true,
                        _a[className + "-text-active"] = isActived,
                        _a));
                    var bottomStyle = {
                        // height: markWidth + '%',
                        marginBottom: '-50%',
                        bottom: (point - min) / range * 100 + "%",
                    };
                    var leftStyle = {
                        width: markWidth + "%",
                        marginLeft: -markWidth / 2 + "%",
                        left: (point - min) / range * 100 + "%",
                    };
                    var style = vertical ? bottomStyle : leftStyle;
                    var markPoint = marks[point];
                    var markPointIsObject = typeof markPoint === 'object' && !Plugin.React.isValidElement(markPoint);
                    var markLabel = markPointIsObject ? markPoint.label : markPoint;
                    var markStyle = markPointIsObject ? __assign({}, style, markPoint.style) : style;
                    return (Plugin.React.createElement("span", { className: markClassName, style: markStyle, key: point }, markLabel));
                });
                return Plugin.React.createElement("div", { className: className }, elements);
            };
            function calcPoints(vertical, marks, dots, step, min, max) {
                var points = Object.keys(marks).map(parseFloat);
                if (dots) {
                    for (var i = min; i <= max; i = i + step) {
                        if (points.indexOf(i) >= 0)
                            continue;
                        points.push(i);
                    }
                }
                return points;
            }
            var Steps = function (_a) {
                var prefixCls = _a.prefixCls, vertical = _a.vertical, marks = _a.marks, dots = _a.dots, step = _a.step, included = _a.included, lowerBound = _a.lowerBound, upperBound = _a.upperBound, max = _a.max, min = _a.min;
                var range = max - min;
                var elements = calcPoints(vertical, marks, dots, step, min, max).map(function (point) {
                    var _a;
                    var offset = Math.abs(point - min) / range * 100 + "%";
                    var style = vertical ? { bottom: offset } : { left: offset };
                    var isActived = (!included && point === upperBound) ||
                        (included && point <= upperBound && point >= lowerBound);
                    var pointClassName = classNames((_a = {},
                        _a[prefixCls + "-dot"] = true,
                        _a[prefixCls + "-dot-active"] = isActived,
                        _a));
                    return Plugin.React.createElement("span", { className: pointClassName, style: style, key: point });
                });
                return Plugin.React.createElement("div", { className: prefixCls + "-step" }, elements);
            };
            // const Track = ({ className, included, vertical, offset, length }: any) => {
            //     const style: any = {
            //         visibility: included ? 'visible' : 'hidden'
            //     };
            //     if (vertical) {
            //         style.bottom = `${offset}%`;
            //         style.height = `${length}%`;
            //     } else {
            //         style.left = `${offset}%`;
            //         style.width = `${length}%`;
            //     }
            //     return <div className={className} style={style} />;
            // };
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            var shallowEqual = LiteMol.Bootstrap.Utils.shallowEqual;
            var ColorPicker = /** @class */ (function (_super) {
                __extends(ColorPicker, _super);
                function ColorPicker() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                ColorPicker.prototype.shouldComponentUpdate = function (nextProps, nextState, nextContext) {
                    return !shallowEqual(this.props, nextProps);
                };
                ColorPicker.prototype.render = function () {
                    var _this = this;
                    var _a = this.props.color, _b = _a.r, r = _b === void 0 ? 1 : _b, _c = _a.g, g = _c === void 0 ? 1 : _c, _d = _a.b, b = _d === void 0 ? 1 : _d;
                    var color = { a: 1, r: 255 * r, g: 255 * g, b: 255 * b };
                    var onChange = function (e) { return _this.props.onChange({ r: e.rgb.r / 255, g: e.rgb.g / 255, b: e.rgb.b / 255 }); };
                    //let type = this.props.type ? this.props.type : 'chrome';
                    var picker = Plugin.React.createElement(Controls.ChromePickerHelper, { color: color, onChangeComplete: onChange });
                    //  type === 'slider'
                    //     ? <Controls.ColorPickerHelper color={color} onChange={onChange} />
                    //     : <Controls.ChromePickerHelper color={color} onChange={onChange} />;
                    return Plugin.React.createElement("div", { className: 'lm-color-picker' }, picker);
                };
                return ColorPicker;
            }(Plugin.React.Component));
            Controls.ColorPicker = ColorPicker;
            var ToggleColorPicker = /** @class */ (function (_super) {
                __extends(ToggleColorPicker, _super);
                function ToggleColorPicker() {
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this.state = { isExpanded: false };
                    return _this;
                }
                ToggleColorPicker.prototype.render = function () {
                    var _this = this;
                    var picker = this.state.isExpanded ? Plugin.React.createElement(ColorPicker, __assign({}, this.props)) : void 0;
                    var clr = this.props.color;
                    var pos = this.props.position ? this.props.position : 'above';
                    //onMouseLeave={() => this.setState({isExpanded: false}) }>
                    return Plugin.React.createElement("div", { className: 'lm-control-row lm-toggle-color-picker lm-toggle-color-picker-' + pos, onMouseLeave: function () { return _this.setState({ isExpanded: false }); } },
                        Plugin.React.createElement("span", null, this.props.label),
                        Plugin.React.createElement("div", null,
                            Plugin.React.createElement(Controls.Button, { onClick: function () { _this.setState({ isExpanded: !_this.state.isExpanded }); }, asBlock: true, customStyle: {
                                    backgroundColor: "rgb(" + ((255 * clr.r) | 0) + ", " + ((255 * clr.g) | 0) + ", " + ((255 * clr.b) | 0) + ")",
                                    color: "rgb(" + ((255 * (1 - clr.r)) | 0) + "," + ((255 * (1 - clr.g)) | 0) + "," + ((255 * (1 - clr.b)) | 0) + ")",
                                } })),
                        picker);
                };
                return ToggleColorPicker;
            }(Plugin.React.Component));
            Controls.ToggleColorPicker = ToggleColorPicker;
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Controls;
        (function (Controls) {
            "use strict";
            function QueryEditor(props) {
                return Plugin.React.createElement("div", { className: 'lm-control-row' },
                    Plugin.React.createElement(Controls.TextBox, { placeholder: 'Enter query...', onChange: props.onChange, value: props.value, onKeyPress: function (e) {
                            if (Controls.isEnter(e) && props.onEnter)
                                props.onEnter.call(null, e);
                        } }));
            }
            Controls.QueryEditor = QueryEditor;
        })(Controls = Plugin.Controls || (Plugin.Controls = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            "use strict";
            var shallowEqual = LiteMol.Bootstrap.Utils.shallowEqual;
            var PureView = /** @class */ (function (_super) {
                __extends(PureView, _super);
                function PureView() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                PureView.prototype.update = function (s) {
                    var ns = LiteMol.Bootstrap.Utils.merge(this.props.state /* long live type system */, s);
                    if (ns !== this.props.state)
                        this.props.onChange(ns);
                };
                PureView.prototype.shouldComponentUpdate = function (nextProps, nextState) {
                    return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
                };
                return PureView;
            }(Plugin.React.Component));
            Views.PureView = PureView;
            var Component = /** @class */ (function (_super) {
                __extends(Component, _super);
                function Component() {
                    // shouldComponentUpdate(nextProps: any, nextState: any) {
                    //     return !shallowEqual(this.props, nextProps);
                    // }
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this.subs = [];
                    return _this;
                }
                Component.prototype.subscribe = function (stream, obs) {
                    var sub = stream.subscribe(obs);
                    this.subs.push(sub);
                    return sub;
                };
                Component.prototype.unsubscribe = function (sub) {
                    var idx = this.subs.indexOf(sub);
                    for (var i = idx; i < this.subs.length - 1; i++) {
                        this.subs[i] = this.subs[i + 1];
                    }
                    sub.dispose();
                    this.subs.pop();
                };
                Component.prototype.componentWillUnmount = function () {
                    for (var _i = 0, _a = this.subs; _i < _a.length; _i++) {
                        var s = _a[_i];
                        s.dispose();
                    }
                    this.subs = [];
                };
                return Component;
            }(Plugin.React.Component));
            Views.Component = Component;
            var ObserverView = /** @class */ (function (_super) {
                __extends(ObserverView, _super);
                function ObserverView() {
                    var _this = _super !== null && _super.apply(this, arguments) || this;
                    _this.subs = [];
                    return _this;
                }
                ObserverView.prototype.subscribe = function (stream, obs) {
                    var sub = stream.subscribe(obs);
                    this.subs.push(sub);
                    return sub;
                };
                ObserverView.prototype.unsubscribe = function (sub) {
                    var idx = this.subs.indexOf(sub);
                    for (var i = idx; i < this.subs.length - 1; i++) {
                        this.subs[i] = this.subs[i + 1];
                    }
                    sub.dispose();
                    this.subs.pop();
                };
                ObserverView.prototype.componentWillUnmount = function () {
                    for (var _i = 0, _a = this.subs; _i < _a.length; _i++) {
                        var s = _a[_i];
                        s.dispose();
                    }
                    this.subs = [];
                };
                return ObserverView;
            }(Plugin.React.Component));
            Views.ObserverView = ObserverView;
            var View = /** @class */ (function (_super) {
                __extends(View, _super);
                function View() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Object.defineProperty(View.prototype, "controller", {
                    get: function () {
                        return this.props.controller;
                    },
                    enumerable: true,
                    configurable: true
                });
                View.prototype.componentWillMount = function () {
                    var _this = this;
                    this.subscribe(this.controller.state, function (s) {
                        _this.forceUpdate();
                    });
                };
                return View;
            }(ObserverView));
            Views.View = View;
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            "use strict";
            var LayoutRegion = LiteMol.Bootstrap.Components.LayoutRegion;
            var Layout = /** @class */ (function (_super) {
                __extends(Layout, _super);
                function Layout() {
                    return _super !== null && _super.apply(this, arguments) || this;
                }
                Layout.prototype.componentDidMount = function () {
                    var _this = this;
                    this.subscribe(LiteMol.Bootstrap.Event.Common.ComponentsChanged.getStream(this.controller.context), function () { return _this.forceUpdate(); });
                };
                Layout.prototype.renderTarget = function (name, target) {
                    var statics = [];
                    var scrollable = [];
                    for (var _i = 0, _a = target.components; _i < _a.length; _i++) {
                        var c = _a[_i];
                        if (c.isStatic)
                            statics.push(Plugin.React.createElement(c.view, { key: c.key, controller: c.controller }));
                        else
                            scrollable.push(Plugin.React.createElement(c.view, { key: c.key, controller: c.controller }));
                    }
                    return Plugin.React.createElement("div", { key: "layout-target-" + name, className: 'lm-layout-region lm-layout-' + target.cssClass },
                        statics.length ? Plugin.React.createElement("div", { className: 'lm-layout-static' }, statics) : void 0,
                        scrollable.length ? Plugin.React.createElement("div", { className: 'lm-layout-scrollable' }, scrollable) : void 0);
                };
                Layout.prototype.updateTarget = function (name, regionType, layout) {
                    var state = this.controller.latestState;
                    var regionStates = state.regionStates;
                    var region = this.controller.targets[regionType];
                    var show;
                    if (state.hideControls) {
                        show = regionStates !== void 0 && regionStates[regionType] === 'Sticky' && region.components.length > 0;
                    }
                    else if (regionStates && regionStates[regionType] === 'Hidden') {
                        show = false;
                    }
                    else {
                        show = region.components.length > 0;
                    }
                    if (show) {
                        layout.regions.push(this.renderTarget(name, region));
                    }
                    else {
                        layout.layoutClass += ' lm-layout-hide-' + name;
                    }
                };
                Layout.prototype.render = function () {
                    var layoutClass = '';
                    var state = this.controller.latestState;
                    var layoutType;
                    if (state.isExpanded) {
                        layoutType = 'lm-layout-expanded';
                    }
                    else {
                        layoutType = 'lm-layout-standard ';
                        switch (state.collapsedControlsLayout) {
                            case LiteMol.Bootstrap.Components.CollapsedControlsLayout.Outside:
                                layoutType += 'lm-layout-standard-outside';
                                break;
                            case LiteMol.Bootstrap.Components.CollapsedControlsLayout.Landscape:
                                layoutType += 'lm-layout-standard-landscape';
                                break;
                            case LiteMol.Bootstrap.Components.CollapsedControlsLayout.Portrait:
                                layoutType += 'lm-layout-standard-portrait';
                                break;
                            default:
                                layoutType += 'lm-layout-standard-outside';
                                break;
                        }
                    }
                    var targets = this.controller.targets;
                    var regions = [this.renderTarget('main', targets[LayoutRegion.Main])];
                    var layout = { regions: regions, layoutClass: layoutClass };
                    this.updateTarget('top', LayoutRegion.Top, layout);
                    this.updateTarget('right', LayoutRegion.Right, layout);
                    this.updateTarget('bottom', LayoutRegion.Bottom, layout);
                    this.updateTarget('left', LayoutRegion.Left, layout);
                    layoutClass = layout.layoutClass;
                    var root = targets[LayoutRegion.Root].components.map(function (c) { return Plugin.React.createElement(c.view, { key: c.key, controller: c.controller }); });
                    return Plugin.React.createElement("div", { className: 'lm-plugin' },
                        Plugin.React.createElement("div", { className: 'lm-plugin-content ' + layoutType },
                            Plugin.React.createElement("div", { className: layoutClass },
                                regions,
                                root)));
                };
                return Layout;
            }(Views.View));
            Views.Layout = Layout;
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Transform;
            (function (Transform) {
                "use strict";
                var ControllerBase = /** @class */ (function (_super) {
                    __extends(ControllerBase, _super);
                    function ControllerBase() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Object.defineProperty(ControllerBase.prototype, "params", {
                        get: function () {
                            return this.controller.latestState.params;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    ControllerBase.prototype.updateParams = function (p) {
                        this.controller.updateParams(p);
                    };
                    ControllerBase.prototype.autoUpdateParams = function (p) {
                        this.controller.autoUpdateParams(p);
                    };
                    ControllerBase.prototype.getPersistentState = function (prop, defaultValue) {
                        return this.controller.context.transforms.getPersistentState(this.controller.transformer, this.transformSourceEntity, prop, defaultValue);
                    };
                    ControllerBase.prototype.setPersistentState = function (prop, value) {
                        if (this.controller.context.transforms.setPersistentState(this.controller.transformer, this.transformSourceEntity, prop, value)) {
                            this.forceUpdate();
                        }
                    };
                    Object.defineProperty(ControllerBase.prototype, "transformSourceEntity", {
                        get: function () {
                            return this.isUpdate ? this.controller.entity.parent : this.controller.entity;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(ControllerBase.prototype, "isUpdate", {
                        get: function () {
                            return this.controller.isUpdate;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Object.defineProperty(ControllerBase.prototype, "canApply", {
                        get: function () {
                            var state = this.controller.latestState;
                            var base = state.canApply && (!this.isUpdate || state.isDirty) && !state.isBusy;
                            if (base && this.isUpdate && state.parametersAutoUpdating)
                                return false;
                            return base;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    ControllerBase.prototype.applyEnter = function (e) {
                        if (!this.canApply)
                            return;
                        e.target.blur();
                        this.controller.apply();
                    };
                    ControllerBase.prototype.render = function () {
                        var _this = this;
                        var isUpdate = this.isUpdate;
                        var state = this.controller.latestState;
                        var issues = state.issues;
                        var hasError = issues && issues.length;
                        var isBusy = state.isBusy;
                        var offMsg = isBusy ? 'Working...' : isUpdate && !hasError ? 'Nothing to update' : (issues ? issues[0] : void 0);
                        var t = this.controller.transformer.info;
                        var commit = Plugin.React.createElement(Plugin.Controls.CommitButton, { action: function () { return _this.controller.apply(); }, isOn: this.canApply, title: issues && issues.length ? issues[0] : this.canApply ? isUpdate ? 'An update will remove all child nodes.' : void 0 : void 0, on: isUpdate ? 'Update' : this.props.isAction ? 'Apply' : 'Add', off: offMsg });
                        var showCommit = this.canApply || hasError;
                        var header = this.props.customHeader
                            ? this.props.customHeader
                            : (isUpdate ? 'Update ' : '') + t.name;
                        var isExpanded = this.getPersistentState('isExpanded', true);
                        return Plugin.React.createElement("div", { className: 'lm-transformer-wrapper' },
                            Plugin.React.createElement(Plugin.Controls.Panel, { header: header, badge: this.props.hideBadge ? void 0 : Plugin.React.createElement(Views.Entity.Badge, { type: t.to[0].info }), className: 'lm-control lm-transformer lm-panel-' + t.to[0].info.typeClass, key: t.id, title: t.description, isExpanded: isExpanded, onExpand: function (e) { _this.setPersistentState('isExpanded', e); }, description: this.controller.transformer.info.description, topRightAction: this.props.showVisibilityIcon ? Plugin.React.createElement(Views.Entity.VisibilityControl, { entity: this.controller.entity }) : void 0 },
                                this.renderControls(),
                                showCommit ? commit : void 0));
                    };
                    return ControllerBase;
                }(Views.View));
                Transform.ControllerBase = ControllerBase;
                var Empty = /** @class */ (function (_super) {
                    __extends(Empty, _super);
                    function Empty() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Empty.prototype.renderControls = function () {
                        return Plugin.React.createElement("div", null);
                    };
                    return Empty;
                }(Transform.ControllerBase));
                Transform.Empty = Empty;
                var View = /** @class */ (function (_super) {
                    __extends(View, _super);
                    function View() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    View.prototype.render = function () {
                        var ctx = this.controller.context;
                        var plugin = ctx.plugin;
                        var state = this.controller.latestState;
                        var transforms = state.transforms;
                        var views = transforms.map(function (t) {
                            var v = plugin.getTransformerInfo(t.transformer).view;
                            return Plugin.React.createElement(v, { controller: t, key: t.transformer.info.id + '-' + t.entity.id });
                        });
                        if (state.update) {
                            var v = plugin.getTransformerInfo(state.update.transformer).view;
                            views.push(Plugin.React.createElement(v, { controller: state.update, key: state.update.transformer.info.id + '-' + state.update.entity.id }));
                        }
                        return Plugin.React.createElement("div", { className: 'lm-transform-view' }, views);
                    };
                    return View;
                }(Views.View));
                Transform.View = View;
                Transform.TransparencyControl = function (props) {
                    var d = props.definition.alpha;
                    return Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Opacity', onChange: function (v) { return props.onChange({ alpha: v, writeDepth: props.definition.writeDepth }); }, min: 0, max: 1, step: 0.01, value: d });
                };
                var Updater = /** @class */ (function (_super) {
                    __extends(Updater, _super);
                    function Updater() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Updater.prototype.componentWillMount = function () {
                        var _this = this;
                        _super.prototype.componentWillMount.call(this);
                        this.subscribe(LiteMol.Bootstrap.Event.Tree.NodeUpdated.getStream(this.controller.context), function (s) {
                            var c = _this.controller.latestState.controller;
                            var e = c && c.entity;
                            if (s.data === e)
                                _this.forceUpdate();
                        });
                    };
                    Updater.prototype.render = function () {
                        var c = this.controller.latestState.controller;
                        if (!c)
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        var ctx = this.controller.context;
                        var plugin = ctx.plugin;
                        var v = plugin.getTransformerInfo(c.transformer).view;
                        if (!v) {
                            console.warn("Count not find view for updater (" + c.transformer.info.id + "), please register it.");
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        }
                        return Plugin.React.createElement(v, { controller: c, key: c.transformer.info.id + '-' + c.entity.id, customHeader: this.controller.header, hideBadge: true, showVisibilityIcon: true });
                    };
                    return Updater;
                }(Views.View));
                Transform.Updater = Updater;
                var Action = /** @class */ (function (_super) {
                    __extends(Action, _super);
                    function Action() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Action.prototype.render = function () {
                        var c = this.controller.latestState.controller;
                        if (!c)
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        var ctx = this.controller.context;
                        var plugin = ctx.plugin;
                        var v = plugin.getTransformerInfo(c.transformer).view;
                        if (!v) {
                            console.warn("Count not find view for updater (" + c.transformer.info.id + "), please register it.");
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        }
                        return Plugin.React.createElement(v, { controller: c, key: c.transformer.info.id + '-' + c.entity.id, customHeader: this.controller.header, hideBadge: true, isAction: true });
                    };
                    return Action;
                }(Views.View));
                Transform.Action = Action;
            })(Transform = Views.Transform || (Views.Transform = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Transform;
            (function (Transform) {
                var Data;
                (function (Data) {
                    "use strict";
                    var Download = /** @class */ (function (_super) {
                        __extends(Download, _super);
                        function Download() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        Download.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Entity.Data.Types, caption: function (s) { return s; }, current: params.type, onChange: function (o) { return _this.updateParams({ type: o, responseCompression: LiteMol.Bootstrap.Utils.DataCompressionMethod.None }); }, label: 'Type' }),
                                params.type === 'Binary'
                                    ? Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: ['None', 'Gzip'], caption: function (s) { return s; }, current: params.responseCompression === LiteMol.Bootstrap.Utils.DataCompressionMethod.Gzip ? 'Gzip' : 'None', onChange: function (o) { return _this.updateParams({ responseCompression: o === 'None' ? LiteMol.Bootstrap.Utils.DataCompressionMethod.None : LiteMol.Bootstrap.Utils.DataCompressionMethod.Gzip }); }, label: 'Compression', title: 'Specify the compression of the data. Usually only appliable if you downloading "raw" files.' })
                                    : void 0,
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.url, onChange: function (v) { return _this.updateParams({ url: v }); }, label: 'URL', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Enter URL...' }));
                        };
                        return Download;
                    }(Transform.ControllerBase));
                    Data.Download = Download;
                    var OpenFile = /** @class */ (function (_super) {
                        __extends(OpenFile, _super);
                        function OpenFile() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        OpenFile.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            var state = this.controller.latestState;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Entity.Data.Types, caption: function (s) { return s; }, current: params.type, onChange: function (o) { return _this.updateParams({ type: o }); }, label: 'Type' }),
                                Plugin.React.createElement("div", { className: 'lm-btn lm-btn-block lm-btn-action lm-loader-lm-btn-file', style: { marginTop: '1px' } },
                                    params.file ? params.file.name : 'Select a file...',
                                    " ",
                                    Plugin.React.createElement("input", { disabled: state.isBusy, type: 'file', onChange: function (evt) { return _this.updateParams({ file: evt.target.files[0] }); }, multiple: false })));
                        };
                        return OpenFile;
                    }(Transform.ControllerBase));
                    Data.OpenFile = OpenFile;
                    var WithIdField = /** @class */ (function (_super) {
                        __extends(WithIdField, _super);
                        function WithIdField() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        WithIdField.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.id, onChange: function (v) { return _this.updateParams({ id: v }); }, label: 'Id', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Enter PDB id...' }));
                        };
                        return WithIdField;
                    }(Transform.ControllerBase));
                    Data.WithIdField = WithIdField;
                    var WithUrlIdField = /** @class */ (function (_super) {
                        __extends(WithUrlIdField, _super);
                        function WithUrlIdField() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        WithUrlIdField.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.id, onChange: function (v) { return _this.updateParams({ id: v }); }, label: 'URL', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Enter URL...' }));
                        };
                        return WithUrlIdField;
                    }(Transform.ControllerBase));
                    Data.WithUrlIdField = WithUrlIdField;
                })(Data = Transform.Data || (Transform.Data = {}));
            })(Transform = Views.Transform || (Views.Transform = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Transform;
            (function (Transform) {
                var Molecule;
                (function (Molecule) {
                    "use strict";
                    var CreateFromData = /** @class */ (function (_super) {
                        __extends(CreateFromData, _super);
                        function CreateFromData() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateFromData.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Core.Formats.Molecule.SupportedFormats.All, caption: function (s) { return s.name; }, current: params.format, onChange: function (o) { return _this.updateParams({ format: o }); }, label: 'Format' }));
                        };
                        return CreateFromData;
                    }(Transform.ControllerBase));
                    Molecule.CreateFromData = CreateFromData;
                    var DownloadFromUrl = /** @class */ (function (_super) {
                        __extends(DownloadFromUrl, _super);
                        function DownloadFromUrl() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        DownloadFromUrl.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Core.Formats.Molecule.SupportedFormats.All, caption: function (s) { return s.name; }, current: params.format, onChange: function (o) { return _this.updateParams({ format: o }); }, label: 'Format' }),
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.id, onChange: function (v) { return _this.updateParams({ id: v }); }, label: 'URL', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Enter url...' }));
                        };
                        return DownloadFromUrl;
                    }(Transform.ControllerBase));
                    Molecule.DownloadFromUrl = DownloadFromUrl;
                    var OpenFile = /** @class */ (function (_super) {
                        __extends(OpenFile, _super);
                        function OpenFile() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        OpenFile.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            var state = this.controller.latestState;
                            var extensions = LiteMol.Core.Formats.FormatInfo.formatFileFilters(LiteMol.Core.Formats.Molecule.SupportedFormats.All);
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement("div", { className: 'lm-btn lm-btn-block lm-btn-action lm-loader-lm-btn-file', style: { marginTop: '1px' } },
                                    params.file ? params.file.name : 'Select a file...',
                                    " ",
                                    Plugin.React.createElement("input", { disabled: state.isBusy, type: 'file', accept: extensions, onChange: function (evt) { return _this.updateParams({ file: evt.target.files[0] }); }, multiple: false })));
                        };
                        return OpenFile;
                    }(Transform.ControllerBase));
                    Molecule.OpenFile = OpenFile;
                    var InitCoordinateStreaming = /** @class */ (function (_super) {
                        __extends(InitCoordinateStreaming, _super);
                        function InitCoordinateStreaming() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        InitCoordinateStreaming.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.id, onChange: function (v) { return _this.updateParams({ id: v }); }, label: 'Id', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Enter pdb id...' }),
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.server, onChange: function (v) { return _this.updateParams({ server: v }); }, label: 'Server', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Server url...' }));
                        };
                        return InitCoordinateStreaming;
                    }(Transform.ControllerBase));
                    Molecule.InitCoordinateStreaming = InitCoordinateStreaming;
                    var CreateFromMmCif = /** @class */ (function (_super) {
                        __extends(CreateFromMmCif, _super);
                        function CreateFromMmCif() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateFromMmCif.prototype.renderControls = function () {
                            var _this = this;
                            var cif = this.transformSourceEntity;
                            var options = cif.props.dictionary.dataBlocks.map(function (b, i) { return ({ b: b.header, i: i }); });
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: options, caption: function (s) { return s.b; }, current: options[this.params.blockIndex], onChange: function (o) { return _this.updateParams({ blockIndex: o.i }); }, label: 'Source' }));
                        };
                        return CreateFromMmCif;
                    }(Transform.ControllerBase));
                    Molecule.CreateFromMmCif = CreateFromMmCif;
                    var CreateModel = /** @class */ (function (_super) {
                        __extends(CreateModel, _super);
                        function CreateModel() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateModel.prototype.renderControls = function () {
                            var _this = this;
                            var modelCount = this.transformSourceEntity.props.molecule.models.length;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Index', onChange: function (v) { return _this.updateParams({ modelIndex: v - 1 }); }, min: 1, max: modelCount, step: 1, value: (this.params.modelIndex | 0) + 1, title: 'Index of the model.' }));
                        };
                        return CreateModel;
                    }(Transform.ControllerBase));
                    Molecule.CreateModel = CreateModel;
                    var CreateAssembly = /** @class */ (function (_super) {
                        __extends(CreateAssembly, _super);
                        function CreateAssembly() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateAssembly.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            //let model = this.isUpdate ? Bootstrap.Utils.Molecule.findModel(this.transformSourceEntity) : this.entity as Bootstrap.Entity.Molecule.Model;
                            var model = LiteMol.Bootstrap.Utils.Molecule.findModel(this.transformSourceEntity);
                            var asm = model.props.model.data.assemblyInfo;
                            if (!asm)
                                return void 0;
                            var names = asm.assemblies.map(function (a) { return a.name; });
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: names, current: params.name, onChange: function (o) { return _this.updateParams({ name: o }); }, label: 'Name' }));
                        };
                        return CreateAssembly;
                    }(Transform.ControllerBase));
                    Molecule.CreateAssembly = CreateAssembly;
                    var CreateSymmetryMates = /** @class */ (function (_super) {
                        __extends(CreateSymmetryMates, _super);
                        function CreateSymmetryMates() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateSymmetryMates.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            var options = ['Mates', 'Interaction'];
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: options, current: params.type, onChange: function (o) { return _this.updateParams({ type: o }); }, label: 'Type', title: 'Mates: copies whole asymetric unit. Interaction: Includes only residues that are no more than `radius` from the asymetric unit.' }),
                                Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Radius', onChange: function (v) { return _this.updateParams({ radius: v }); }, min: 0, max: 25, step: 0.1, value: params.radius, title: 'Interaction radius.' }));
                        };
                        return CreateSymmetryMates;
                    }(Transform.ControllerBase));
                    Molecule.CreateSymmetryMates = CreateSymmetryMates;
                    var CreateSelection = /** @class */ (function (_super) {
                        __extends(CreateSelection, _super);
                        function CreateSelection() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateSelection.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.TextBoxGroup, { value: params.name, onChange: function (v) { return _this.updateParams({ name: v }); }, label: 'Name', onEnter: function (e) { return _this.applyEnter(e); }, placeholder: 'Optional name...' }),
                                Plugin.React.createElement(Plugin.Controls.QueryEditor, { value: params.queryString, onChange: function (v) { return _this.updateParams({ queryString: v }); }, onEnter: function (e) { return _this.applyEnter(e); } }));
                            //<Controls.TextBoxGroup value={params.queryString} onChange={(v) => this.updateParams({ queryString: v })} onEnter={e => this.applyEnter(e) } label='Query' placeholder='Enter a query...' />
                        };
                        return CreateSelection;
                    }(Transform.ControllerBase));
                    Molecule.CreateSelection = CreateSelection;
                    var CreateMacromoleculeVisual = /** @class */ (function (_super) {
                        __extends(CreateMacromoleculeVisual, _super);
                        function CreateMacromoleculeVisual() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateMacromoleculeVisual.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.updateParams({ polymer: v }); }, value: params.polymer, label: 'Polymer' }),
                                Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.updateParams({ het: v }); }, value: params.het, label: 'HET' }),
                                Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.updateParams({ water: v }); }, value: params.water, label: 'Water' }));
                        };
                        return CreateMacromoleculeVisual;
                    }(Transform.ControllerBase));
                    Molecule.CreateMacromoleculeVisual = CreateMacromoleculeVisual;
                    var CreateVisual = /** @class */ (function (_super) {
                        __extends(CreateVisual, _super);
                        function CreateVisual() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateVisual.prototype.detail = function () {
                            var _this = this;
                            var p = this.params.style.params;
                            return [Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Visualization.Molecule.DetailTypes, caption: function (s) { return s; }, current: p.detail, onChange: function (o) { return _this.controller.updateStyleParams({ detail: o }); }, label: 'Detail' })];
                        };
                        CreateVisual.prototype.cartoons = function () {
                            var _this = this;
                            var p = this.params.style.params;
                            return [
                                Plugin.React.createElement(Plugin.Controls.Toggle, { key: 0, onChange: function (v) { return _this.controller.updateStyleParams({ showDirectionCone: v }); }, value: p.showDirectionCone, label: 'Dir. Cones' }),
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { key: 1, options: LiteMol.Bootstrap.Visualization.Molecule.DetailTypes, caption: function (s) { return s; }, current: p.detail, onChange: function (o) { return _this.controller.updateStyleParams({ detail: o }); }, label: 'Detail' })
                            ];
                        };
                        CreateVisual.prototype.ballsAndSticks = function () {
                            var _this = this;
                            var p = this.params.style.params;
                            var controls = [];
                            var key = 0;
                            controls.push(Plugin.React.createElement(Plugin.Controls.Toggle, { title: 'Scale atoms using their VDW radius.', onChange: function (v) { return _this.controller.updateStyleParams({ useVDW: v }); }, value: p.useVDW, label: 'VDW' }));
                            if (p.useVDW) {
                                controls.push(Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Scale', onChange: function (v) { return _this.controller.updateStyleParams({ vdwScaling: v }); }, min: 0.1, max: 1, step: 0.01, value: p.vdwScaling, title: 'VDW scale factor.' }));
                            }
                            else {
                                controls.push(Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Atom Rds', onChange: function (v) { return _this.controller.updateStyleParams({ atomRadius: v }); }, min: 0.05, max: 2, step: 0.01, value: p.atomRadius, title: 'Atom Radius' }));
                            }
                            controls.push(Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Bond Rds', onChange: function (v) { return _this.controller.updateStyleParams({ bondRadius: v }); }, min: 0.05, max: 1, step: 0.01, value: p.bondRadius, title: 'Bond Radius' }));
                            var maxHbondLength = p.customMaxBondLengths && p.customMaxBondLengths['H'] ? p.customMaxBondLengths['H'] : 1.15;
                            controls.push(Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'H Bond Len', onChange: function (v) { return _this.controller.updateStyleParams({ customMaxBondLengths: __assign({}, p.customMaxBondLengths, { 'H': v }) }); }, min: 0.9, max: 1.5, step: 0.01, value: maxHbondLength, title: 'Maximum H bond length' }));
                            controls.push(Plugin.React.createElement(Plugin.Controls.Toggle, { key: key++, onChange: function (v) { return _this.controller.updateStyleParams({ hideHydrogens: v }); }, value: p.hideHydrogens, label: 'Hide H' }));
                            controls.push(Plugin.React.createElement(Plugin.Controls.OptionsGroup, { key: key++, options: LiteMol.Bootstrap.Visualization.Molecule.DetailTypes, caption: function (s) { return s; }, current: p.detail, onChange: function (o) { return _this.controller.updateStyleParams({ detail: o }); }, label: 'Detail' }));
                            return controls;
                        };
                        CreateVisual.prototype.surface = function () {
                            var _this = this;
                            var params = this.params.style.params;
                            var key = 0;
                            return [
                                Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Probe Radius', onChange: function (v) { return _this.controller.updateStyleParams({ probeRadius: v }); }, min: 0, max: 6, step: 0.1, value: params.probeRadius }),
                                Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Smoothing', onChange: function (v) { return _this.controller.updateStyleParams({ smoothing: v }); }, min: 0, max: 20, step: 1, value: params.smoothing, title: 'Number of laplacian smoothing itrations.' }),
                                Plugin.React.createElement(Plugin.Controls.Toggle, { key: key++, onChange: function (v) { return _this.controller.updateStyleParams({ automaticDensity: v }); }, value: params.automaticDensity, label: 'Auto Detail' }),
                                (params.automaticDensity
                                    ? void 0
                                    : Plugin.React.createElement(Plugin.Controls.Slider, { key: key++, label: 'Detail', onChange: function (v) { return _this.controller.updateStyleParams({ density: v }); }, min: 0.1, max: 3, step: 0.1, value: params.density, title: 'Determines the size of a grid cell (size = 1/detail).' })),
                                Plugin.React.createElement(Plugin.Controls.Toggle, { key: key++, onChange: function (v) { return _this.controller.updateStyleParams({ isWireframe: v }); }, value: params.isWireframe, label: 'Wireframe' })
                            ];
                        };
                        CreateVisual.prototype.createColors = function () {
                            var _this = this;
                            var theme = this.params.style.theme;
                            var isBallsAndSticks = this.params.style.type === 'BallsAndSticks';
                            var controls = theme.colors
                                .filter(function (c, n) { return !isBallsAndSticks ? n !== 'Bond' : true; })
                                .map(function (c, n) { return Plugin.React.createElement(Plugin.Controls.ToggleColorPicker, { key: n, label: n, color: c, onChange: function (c) { return _this.controller.updateThemeColor(n, c); } }); }).toArray();
                            controls.push(Plugin.React.createElement(Transform.TransparencyControl, { definition: theme.transparency, onChange: function (d) { return _this.controller.updateThemeTransparency(d); } }));
                            // controls.push(<Controls.Toggle 
                            //         onChange={v => this.controller.updateStyleTheme({ wireframe: v }) } value={theme.wireframe} label='Wireframe' />);
                            return controls;
                        };
                        CreateVisual.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            var controls;
                            switch (params.style.type) {
                                case 'Surface':
                                    controls = this.surface();
                                    break;
                                case 'BallsAndSticks':
                                    controls = this.ballsAndSticks();
                                    break;
                                case 'Cartoons':
                                    controls = this.cartoons();
                                    break;
                                default:
                                    controls = this.detail();
                                    break;
                            }
                            var desc = function (key) { return LiteMol.Bootstrap.Visualization.Molecule.TypeDescriptions[key]; };
                            var showTypeOptions = this.getPersistentState('showTypeOptions', false);
                            var showThemeOptions = this.getPersistentState('showThemeOptions', false);
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Visualization.Molecule.Types, caption: function (k) { return desc(k).label; }, current: params.style.type, onChange: function (o) { return _this.controller.updateTemplate(o, LiteMol.Bootstrap.Visualization.Molecule.Default.ForType); }, label: 'Type' }), expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: showTypeOptions, onChange: function (e) { return _this.setPersistentState('showTypeOptions', e); } }), options: controls, isExpanded: showTypeOptions }),
                                Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Visualization.Molecule.Default.Themes, caption: function (k) { return k.name; }, current: params.style.theme.template, onChange: function (o) { return _this.controller.updateThemeDefinition(o); }, label: 'Coloring' }), expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: showThemeOptions, onChange: function (e) { return _this.setPersistentState('showThemeOptions', e); } }), options: this.createColors(), isExpanded: showThemeOptions }));
                        };
                        return CreateVisual;
                    }(Transform.ControllerBase));
                    Molecule.CreateVisual = CreateVisual;
                    var CreateLabels = /** @class */ (function (_super) {
                        __extends(CreateLabels, _super);
                        function CreateLabels() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateLabels.prototype.renderControls = function () {
                            var _this = this;
                            var style = this.controller.latestState.params.style;
                            var select = Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Bootstrap.Utils.Molecule.Labels3DKinds, caption: function (k) { return LiteMol.Bootstrap.Utils.Molecule.Labels3DKindLabels[k]; }, current: style.params.kind, onChange: function (o) { return _this.controller.updateStyleParams({ kind: o }); }, label: 'Kind' });
                            var showOptions = this.getPersistentState('showOptions', false);
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: select, expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: showOptions, onChange: function (e) { return _this.setPersistentState('showOptions', e); } }), options: Transform.Labels.optionsControls(this.controller), isExpanded: showOptions }));
                        };
                        return CreateLabels;
                    }(Transform.ControllerBase));
                    Molecule.CreateLabels = CreateLabels;
                })(Molecule = Transform.Molecule || (Transform.Molecule = {}));
            })(Transform = Views.Transform || (Views.Transform = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Transform;
            (function (Transform) {
                var Density;
                (function (Density) {
                    "use strict";
                    var IsoValue = function (props) {
                        return Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: Plugin.React.createElement(Plugin.Controls.Slider, { label: props.isSigma ? 'Iso Value (\u03C3)' : 'Iso Value', onChange: props.onChangeValue, min: props.min, max: props.max, value: props.value, step: 0.001 }), expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: props.view.getPersistentState('showIsoValueType', false), onChange: function (e) { return props.view.setPersistentState('showIsoValueType', e); } }), options: [Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return props.onChangeType(v ? LiteMol.Bootstrap.Visualization.Density.IsoValueType.Sigma : LiteMol.Bootstrap.Visualization.Density.IsoValueType.Absolute); }, value: props.isSigma, label: 'Relative (\\u03C3)' })], isExpanded: props.view.getPersistentState('showIsoValueType', false) });
                    };
                    function isoValueAbsoluteToSigma(data, value, min, max) {
                        var ret = (value - data.valuesInfo.mean) / data.valuesInfo.sigma;
                        if (ret > max)
                            return max;
                        if (ret < min)
                            return min;
                        return ret;
                    }
                    function isoValueSigmaToAbsolute(data, value) {
                        var ret = data.valuesInfo.mean + value * data.valuesInfo.sigma;
                        if (ret > data.valuesInfo.max)
                            return data.valuesInfo.max;
                        if (ret < data.valuesInfo.min)
                            return data.valuesInfo.min;
                        return ret;
                    }
                    var ParseData = /** @class */ (function (_super) {
                        __extends(ParseData, _super);
                        function ParseData() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        ParseData.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            var round = LiteMol.Bootstrap.Utils.round;
                            if (this.isUpdate) {
                                var data = this.controller.entity.props.data;
                                return Plugin.React.createElement("div", null,
                                    Plugin.React.createElement(Plugin.Controls.RowText, { label: 'Format', value: params.format.name }),
                                    Plugin.React.createElement(Plugin.Controls.RowText, { label: 'Sigma', value: round(data.valuesInfo.sigma, 3) }),
                                    Plugin.React.createElement(Plugin.Controls.RowText, { label: 'Mean', value: round(data.valuesInfo.mean, 3) }),
                                    Plugin.React.createElement(Plugin.Controls.RowText, { label: 'Value Range', value: "[" + round(data.valuesInfo.min, 3) + ", " + round(data.valuesInfo.max, 3) + "]" }));
                            }
                            return Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: LiteMol.Core.Formats.Density.SupportedFormats.All, caption: function (s) { return s.name; }, current: params.format, onChange: function (o) { return _this.updateParams({ format: o }); }, label: 'Format' }));
                        };
                        return ParseData;
                    }(Transform.ControllerBase));
                    Density.ParseData = ParseData;
                    var CreateVisual = /** @class */ (function (_super) {
                        __extends(CreateVisual, _super);
                        function CreateVisual() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateVisual.prototype.surface = function () {
                            var _this = this;
                            var data = LiteMol.Bootstrap.Tree.Node.findClosestNodeOfType(this.transformSourceEntity, [LiteMol.Bootstrap.Entity.Density.Data]);
                            var params = this.params.style.params;
                            var isSigma = params.isoValueType !== LiteMol.Bootstrap.Visualization.Density.IsoValueType.Absolute;
                            var values = data.props.data.valuesInfo;
                            var min = isSigma
                                ? (values.min - values.mean) / values.sigma
                                : values.min;
                            var max = isSigma
                                ? (values.max - values.mean) / values.sigma
                                : values.max;
                            return Plugin.React.createElement(IsoValue, { view: this, onChangeValue: function (v) { return _this.controller.updateStyleParams({ isoValue: v }); }, onChangeType: function (v) {
                                    if (v === params.isoValueType)
                                        return;
                                    if (v === LiteMol.Bootstrap.Visualization.Density.IsoValueType.Absolute) {
                                        _this.controller.updateStyleParams({ isoValue: isoValueSigmaToAbsolute(data.props.data, params.isoValue), isoValueType: v });
                                    }
                                    else {
                                        _this.controller.updateStyleParams({ isoValue: isoValueAbsoluteToSigma(data.props.data, params.isoValue, -5, 5), isoValueType: v });
                                    }
                                }, min: min, max: max, isSigma: isSigma, value: params.isoValue });
                        };
                        CreateVisual.prototype.colors = function () {
                            var _this = this;
                            var params = this.params.style.params;
                            var theme = this.params.style.theme;
                            var uc = theme.colors.get('Uniform');
                            var uniform = Plugin.React.createElement(Plugin.Controls.ToggleColorPicker, { key: 'Uniform', label: 'Color', color: uc, onChange: function (c) { return _this.controller.updateThemeColor('Uniform', c); } });
                            var controls = [];
                            // theme.colors!
                            //     .filter((c, n) => n !== 'Uniform')
                            //     .map((c, n) => <Controls.ToggleColorPicker  key={n} label={n!} color={c!} onChange={c => this.controller.updateThemeColor(n!, c) } />).toArray();
                            controls.push(Plugin.React.createElement(Transform.TransparencyControl, { definition: theme.transparency, onChange: function (d) { return _this.controller.updateThemeTransparency(d); } }));
                            //controls.push(<Controls.Slider label='Smoothing' onChange={v => this.controller.updateStyleParams({ smoothing: v  })}  min={0} max={10} step={1} value={visualParams.smoothing!} title='Number of laplacian smoothing itrations.' />);
                            controls.push(Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.controller.updateStyleParams({ isWireframe: v }); }, value: params.isWireframe, label: 'Wireframe' }));
                            var showThemeOptions = this.getPersistentState('showThemeOptions', false);
                            return Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: uniform, expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: showThemeOptions, onChange: function (e) { return _this.setPersistentState('showThemeOptions', e); } }), options: controls, isExpanded: showThemeOptions });
                        };
                        CreateVisual.prototype.renderControls = function () {
                            return Plugin.React.createElement("div", null,
                                this.surface(),
                                this.colors());
                        };
                        return CreateVisual;
                    }(Transform.ControllerBase));
                    Density.CreateVisual = CreateVisual;
                    var CreateVisualBehaviour = /** @class */ (function (_super) {
                        __extends(CreateVisualBehaviour, _super);
                        function CreateVisualBehaviour() {
                            return _super !== null && _super.apply(this, arguments) || this;
                        }
                        CreateVisualBehaviour.prototype.surface = function () {
                            var _this = this;
                            var data = LiteMol.Bootstrap.Tree.Node.findClosestNodeOfType(this.transformSourceEntity, [LiteMol.Bootstrap.Entity.Density.Data]);
                            var params = this.params;
                            var visualParams = params.style.params;
                            var isSigma = visualParams.isoValueType !== LiteMol.Bootstrap.Visualization.Density.IsoValueType.Absolute;
                            return Plugin.React.createElement(IsoValue, { view: this, onChangeValue: function (v) { return _this.controller.updateStyleParams({ isoValue: v }); }, onChangeType: function (v) {
                                    if (v === visualParams.isoValueType)
                                        return;
                                    if (v === LiteMol.Bootstrap.Visualization.Density.IsoValueType.Absolute) {
                                        _this.controller.updateStyleParams({ isoValue: isoValueSigmaToAbsolute(data.props.data, visualParams.isoValue), isoValueType: v });
                                    }
                                    else {
                                        _this.controller.updateStyleParams({ isoValue: isoValueAbsoluteToSigma(data.props.data, visualParams.isoValue, params.isoSigmaMin, params.isoSigmaMax), isoValueType: v });
                                    }
                                }, min: isSigma ? params.isoSigmaMin : data.props.data.valuesInfo.min, max: isSigma ? params.isoSigmaMax : data.props.data.valuesInfo.max, isSigma: isSigma, value: visualParams.isoValue });
                        };
                        CreateVisualBehaviour.prototype.colors = function () {
                            var _this = this;
                            var params = this.params.style.params;
                            var theme = this.params.style.theme;
                            var uc = theme.colors.get('Uniform');
                            var uniform = Plugin.React.createElement(Plugin.Controls.ToggleColorPicker, { key: 'Uniform', label: 'Color', color: uc, onChange: function (c) { return _this.controller.updateThemeColor('Uniform', c); } });
                            var controls = [];
                            // theme.colors!
                            //     .filter((c, n) => n !== 'Uniform')
                            //     .map((c, n) => <Controls.ToggleColorPicker  key={n} label={n!} color={c!} onChange={c => this.controller.updateThemeColor(n!, c) } />).toArray();
                            controls.push(Plugin.React.createElement(Transform.TransparencyControl, { definition: theme.transparency, onChange: function (d) { return _this.controller.updateThemeTransparency(d); } }));
                            //controls.push(<Controls.Slider label='Smoothing' onChange={v => this.controller.updateStyleParams({ smoothing: v  })}  min={0} max={10} step={1} value={visualParams.smoothing!} title='Number of laplacian smoothing itrations.' />);
                            controls.push(Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.controller.updateStyleParams({ isWireframe: v }); }, value: params.isWireframe, label: 'Wireframe' }));
                            var showThemeOptions = this.getPersistentState('showThemeOptions', false);
                            return Plugin.React.createElement(Plugin.Controls.ExpandableGroup, { select: uniform, expander: Plugin.React.createElement(Plugin.Controls.ControlGroupExpander, { isExpanded: showThemeOptions, onChange: function (e) { return _this.setPersistentState('showThemeOptions', e); } }), options: controls, isExpanded: showThemeOptions });
                        };
                        CreateVisualBehaviour.prototype.show = function () {
                            var _this = this;
                            var selLabel = 'Around Selection';
                            var allLabel = 'Everything';
                            var params = this.params;
                            return Plugin.React.createElement(Plugin.Controls.OptionsGroup, { options: [selLabel, allLabel], caption: function (s) { return s; }, current: params.showFull ? allLabel : selLabel, onChange: function (o) { return _this.autoUpdateParams({ showFull: o === allLabel }); }, label: 'Show' });
                        };
                        CreateVisualBehaviour.prototype.renderControls = function () {
                            var _this = this;
                            var params = this.params;
                            return Plugin.React.createElement("div", null,
                                this.surface(),
                                this.colors(),
                                this.show(),
                                !params.showFull
                                    ? Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Radius', onChange: function (v) { return _this.autoUpdateParams({ radius: v }); }, min: params.minRadius !== void 0 ? params.minRadius : 0, max: params.maxRadius !== void 0 ? params.maxRadius : 10, step: 0.005, value: params.radius })
                                    : void 0);
                        };
                        return CreateVisualBehaviour;
                    }(Transform.ControllerBase));
                    Density.CreateVisualBehaviour = CreateVisualBehaviour;
                })(Density = Transform.Density || (Transform.Density = {}));
            })(Transform = Views.Transform || (Views.Transform = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2017 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Transform;
            (function (Transform) {
                var Labels;
                (function (Labels) {
                    "use strict";
                    function optionsControls(controller) {
                        var style = controller.latestState.params.style;
                        var colors = style.theme.colors
                            .map(function (c, n) { return Plugin.React.createElement(Plugin.Controls.ToggleColorPicker, { key: n, label: n === 'Uniform' ? 'Font' : n, color: c, onChange: function (c) { return controller.updateThemeColor(n, c); } }); }).toArray();
                        return [
                            Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Size', onChange: function (v) { return controller.updateThemeVariable('sizeFactor', v); }, min: 0.1, max: 10, step: 0.1, value: (style.theme.variables && style.theme.variables.get('sizeFactor')) || 1.0, title: 'Font size.' }),
                            Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Outline', onChange: function (v) { return controller.updateThemeVariable('outlineWidth', v); }, min: 0.0, max: 0.3, step: 0.001, value: (style.theme.variables && style.theme.variables.get('outlineWidth')) || 0.0, title: 'Font outline.' }),
                            Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Offset', onChange: function (v) { return controller.updateThemeVariable('zOffset', v); }, min: 0.0, max: 5.0, step: 0.1, value: (style.theme.variables && style.theme.variables.get('zOffset')) || 0.0, title: 'Label offset.' }),
                            Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Bg. Opacity', onChange: function (v) { return controller.updateThemeVariable('backgroundOpacity', v); }, min: 0.0, max: 1.0, step: 0.01, value: (style.theme.variables && style.theme.variables.get('backgroundOpacity')) || 0.0, title: 'Background opacity.' })
                        ].concat(colors);
                    }
                    Labels.optionsControls = optionsControls;
                })(Labels = Transform.Labels || (Transform.Labels = {}));
            })(Transform = Views.Transform || (Views.Transform = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Context;
            (function (Context) {
                "use strict";
                var EntryType = LiteMol.Bootstrap.Service.Logger.EntryType;
                var Log = /** @class */ (function (_super) {
                    __extends(Log, _super);
                    function Log() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.wrapper = void 0;
                        return _this;
                    }
                    Log.prototype.componentWillMount = function () {
                        var _this = this;
                        _super.prototype.componentWillMount.call(this);
                        this.subscribe(LiteMol.Bootstrap.Event.Common.LayoutChanged.getStream(this.controller.context), function () { return _this.scrollToBottom(); });
                    };
                    Log.prototype.componentDidUpdate = function () {
                        this.scrollToBottom();
                    };
                    Log.prototype.scrollToBottom = function () {
                        var log = this.wrapper;
                        if (log)
                            log.scrollTop = log.scrollHeight - log.clientHeight - 1;
                    };
                    Log.prototype.render = function () {
                        var _this = this;
                        var entries = this.controller.latestState.entries;
                        return Plugin.React.createElement("div", { className: 'lm-log-wrap' },
                            Plugin.React.createElement("div", { className: 'lm-log', ref: function (log) { return _this.wrapper = log; } },
                                Plugin.React.createElement("ul", { className: 'lm-list-unstyled' }, entries.map(function (entry, i, arr) {
                                    // let msg: any;
                                    // switch (e.type) {
                                    //     case EntryType.Message:
                                    //     msg = <div className='lm-log-entry'>{e.message}</div>;
                                    //     break;
                                    //     case EntryType.Error:
                                    //     msg = <div className='lm-log-entry'><span className='label label-danger'>Error</span> {e.message}</div>;
                                    //     break;
                                    //     case EntryType.Warning:
                                    //     msg = <div className='lm-log-entry'><span className='label label-warning'>Warning</span> {e.message}</div>;
                                    //     break;
                                    //     case EntryType.Info:
                                    //     msg = <div className='lm-log-entry'><span className='label label-info'>Info</span> {e.message}</div>;
                                    //     break;
                                    // }
                                    var e = entry;
                                    var t = LiteMol.Bootstrap.Utils.formatTime(e.timestamp);
                                    return Plugin.React.createElement("li", { key: i },
                                        Plugin.React.createElement("div", { className: 'lm-log-entry-badge lm-log-entry-' + EntryType[e.type].toLowerCase() }),
                                        Plugin.React.createElement("div", { className: 'lm-log-timestamp' }, t),
                                        Plugin.React.createElement("div", { className: 'lm-log-entry' }, e.message));
                                }))));
                    };
                    return Log;
                }(Views.View));
                Context.Log = Log;
            })(Context = Views.Context || (Views.Context = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Context;
            (function (Context) {
                "use strict";
                var TaskState = /** @class */ (function (_super) {
                    __extends(TaskState, _super);
                    function TaskState() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    TaskState.prototype.render = function () {
                        var info = this.props.info;
                        return Plugin.React.createElement("div", { className: 'lm-task-state' },
                            Plugin.React.createElement("div", null,
                                info.abort ? Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { return info.abort.call(null); }, style: 'remove', icon: 'abort', title: 'Abort', customClass: 'lm-btn-icon' }) : void 0,
                                Plugin.React.createElement("div", null,
                                    info.name,
                                    ": ",
                                    info.message)));
                    };
                    return TaskState;
                }(Plugin.React.Component));
                var Overlay = /** @class */ (function (_super) {
                    __extends(Overlay, _super);
                    function Overlay() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Overlay.prototype.render = function () {
                        var state = this.controller.latestState;
                        if (!state.tasks.count())
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        var tasks = [];
                        state.tasks.forEach(function (t, k) { return tasks.push(Plugin.React.createElement(TaskState, { key: k, info: t })); });
                        //    tasks.push(<span><TaskState key={-1} info={{ message: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut te', name: 'occaecat ', abort: () => {} }} /><br/></span>)
                        //    tasks.push(<br/>)
                        //    tasks.push(<TaskState key={-2} info={{ message: 'uam metus. Duis risus. F', name: 'dsads' }} />)
                        //   tasks.push(<TaskState key={-3} info={{ message: 'm dapibus fermentum ipsum. Lorem ipsum dolor', name: 'bibendum ', abort: () => {} }} />)          
                        return Plugin.React.createElement("div", { className: 'lm-overlay' },
                            Plugin.React.createElement("div", { className: 'lm-overlay-background' }),
                            Plugin.React.createElement("div", { className: 'lm-overlay-content-wrap' },
                                Plugin.React.createElement("div", { className: 'lm-overlay-content' },
                                    Plugin.React.createElement("div", null, tasks))));
                    };
                    return Overlay;
                }(Views.View));
                Context.Overlay = Overlay;
                var BackgroundTasks = /** @class */ (function (_super) {
                    __extends(BackgroundTasks, _super);
                    function BackgroundTasks() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    BackgroundTasks.prototype.render = function () {
                        var state = this.controller.latestState;
                        if (!state.tasks.count())
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        var tasks = [];
                        state.tasks.forEach(function (t, k) { return tasks.push(Plugin.React.createElement(TaskState, { key: k, info: t, isSmall: true })); });
                        //    tasks.push(<TaskState key={-1} isSmall={true} info={{ message: 's diam. Vivamus luctus egestas l', name: 'bibendum ', abort: () => {} }} />)
                        //    tasks.push(<TaskState key={-3} isSmall={true} info={{ message: 'ccaecat cupidatat non proid', name: 'dsadsad', abort: () => {} }} />)
                        //    tasks.push(<TaskState key={-2} isSmall={true} info={{ message: 'modo dui eget wisi. Nullam sap', name: 'dsads' }} />)
                        return Plugin.React.createElement("div", { className: 'lm-background-tasks' }, tasks);
                    };
                    return BackgroundTasks;
                }(Views.View));
                Context.BackgroundTasks = BackgroundTasks;
            })(Context = Views.Context || (Views.Context = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Context;
            (function (Context) {
                "use strict";
                var ToastEntry = /** @class */ (function (_super) {
                    __extends(ToastEntry, _super);
                    function ToastEntry() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    ToastEntry.prototype.hide = function () {
                        var entry = this.props.entry;
                        (entry.hide || function () { }).call(null);
                    };
                    ToastEntry.prototype.render = function () {
                        var _this = this;
                        var entry = this.props.entry;
                        var message = typeof entry.message === 'string'
                            ? Plugin.React.createElement("div", { dangerouslySetInnerHTML: { __html: entry.message } })
                            : Plugin.React.createElement("div", null, entry.message);
                        return Plugin.React.createElement("div", { className: 'lm-toast-entry' },
                            Plugin.React.createElement("div", { className: 'lm-toast-title', onClick: function () { return _this.hide(); } }, entry.title),
                            Plugin.React.createElement("div", { className: 'lm-toast-message' }, message),
                            Plugin.React.createElement("div", { className: 'lm-toast-clear' }),
                            Plugin.React.createElement("div", { className: 'lm-toast-hide' },
                                Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { return _this.hide(); }, style: 'link', icon: 'abort', title: 'Hide', customClass: 'lm-btn-icon' })));
                    };
                    return ToastEntry;
                }(Plugin.React.Component));
                var Toast = /** @class */ (function (_super) {
                    __extends(Toast, _super);
                    function Toast() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Toast.prototype.render = function () {
                        var state = this.controller.latestState;
                        if (!state.entries.count())
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        var entries = [];
                        state.entries.forEach(function (t, k) { return entries.push(t); });
                        entries.sort(function (x, y) { return x.serialNumber - y.serialNumber; });
                        var toasts = entries.map(function (e) { return Plugin.React.createElement(ToastEntry, { key: e.serialNumber, entry: e }); });
                        // toasts.push(<ToastEntry key={0} entry={{ message: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut te.', title: 'Test Title' } as any} />);
                        // toasts.push(<ToastEntry key={1} entry={{ message: 'Lorem ipsum, consectetuer adipiscin te.', title: 'Title' } as any} />);
                        return Plugin.React.createElement("div", { className: 'lm-toast-container' },
                            Plugin.React.createElement("div", null, toasts));
                    };
                    return Toast;
                }(Views.View));
                Context.Toast = Toast;
            })(Context = Views.Context || (Views.Context = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Entity;
            (function (Entity_2) {
                "use strict";
                Entity_2.VisibilityControl = function (props) {
                    var e = props.entity;
                    var command = function () {
                        LiteMol.Bootstrap.Command.Entity.SetVisibility.dispatch(e.tree.context, { entity: e, visible: e.state.visibility === 0 /* Full */ ? false : true });
                    };
                    var state = e.state.visibility;
                    var cls, title;
                    if (state === 0 /* Full */) {
                        cls = 'full';
                        title = 'Hide';
                    }
                    else if (state === 2 /* None */) {
                        cls = 'none';
                        title = 'Show';
                    }
                    else {
                        cls = 'partial';
                        title = 'Show';
                    }
                    return Plugin.React.createElement(Plugin.Controls.Button, { title: title, onClick: command, icon: 'visual-visibility', style: 'link', customClass: "lm-entity-tree-entry-toggle-visible lm-entity-tree-entry-toggle-visible-" + cls });
                };
                var Entity = /** @class */ (function (_super) {
                    __extends(Entity, _super);
                    function Entity() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.renderedVersion = -1;
                        _this.root = void 0;
                        return _this;
                    }
                    Entity.prototype.ensureVisible = function () {
                        if (this.ctx.currentEntity === this.props.node) {
                            if (this.root)
                                this.props.tree.scrollIntoView(this.root);
                        }
                    };
                    Entity.prototype.componentDidMount = function () {
                        this.ensureVisible();
                    };
                    Entity.prototype.componentDidUpdate = function () {
                        this.ensureVisible();
                    };
                    Object.defineProperty(Entity.prototype, "node", {
                        get: function () {
                            return this.props.node;
                        },
                        enumerable: true,
                        configurable: true
                    });
                    Entity.prototype.shouldComponentUpdate = function (nextProps, nextState, nextContext) {
                        return this.node.version !== this.renderedVersion;
                    };
                    Entity.prototype.componentWillMount = function () {
                        var _this = this;
                        this.ctx = this.props.node.tree.context;
                        var node = this.node;
                        //this.state.version = node.version;                            
                        this.subscribe(LiteMol.Bootstrap.Event.Tree.NodeUpdated.getStream(this.ctx), function (e) {
                            if (e.data === node) {
                                if (node.version !== _this.renderedVersion)
                                    _this.forceUpdate();
                                if (_this.ctx.currentEntity === node && _this.isFullyBound()) {
                                    setTimeout(LiteMol.Bootstrap.Command.Entity.SetCurrent.dispatch(_this.ctx, node.children[0]), 0);
                                }
                            }
                        });
                    };
                    Entity.prototype.highlight = function (isOn) {
                        var node = this.node;
                        LiteMol.Bootstrap.Command.Entity.Highlight.dispatch(this.ctx, { entities: this.ctx.select(LiteMol.Bootstrap.Tree.Selection.byValue(node).subtree()), isOn: isOn });
                    };
                    Entity.prototype.row = function (childCount) {
                        var _this = this;
                        var entity = this.props.node;
                        var props = entity.props;
                        var isRoot = entity.parent === entity;
                        var title = props.label;
                        if (props.description)
                            title += ' (' + props.description + ')';
                        return Plugin.React.createElement("div", { className: 'lm-entity-tree-entry-body' + (this.ctx.currentEntity === entity ? ' lm-entity-tree-entry-current' : '') + (this.isOnCurrentPath() ? ' lm-entity-tree-entry-current-path' : ''), ref: function (root) { return _this.root = root; } },
                            Plugin.React.createElement(Entity_2.Badge, { type: entity.type.info }),
                            Plugin.React.createElement("div", { className: 'lm-entity-tree-entry-label-wrap' },
                                Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { return LiteMol.Bootstrap.Command.Entity.SetCurrent.dispatch(_this.ctx, entity); }, customClass: 'lm-entity-tree-entry-label', style: 'link', title: title },
                                    Plugin.React.createElement("span", null,
                                        props.label,
                                        Plugin.React.createElement("span", { className: 'lm-entity-tree-entry-label-tag' }, props.description ? ' ' + props.description : void 0)))),
                            !isRoot || childCount
                                ? Plugin.React.createElement(Plugin.Controls.Button, { title: 'Remove', onClick: function () { return LiteMol.Bootstrap.Command.Tree.RemoveNode.dispatch(entity.tree.context, entity); }, icon: 'remove', style: 'link', customClass: 'lm-entity-tree-entry-remove' })
                                : void 0,
                            isRoot && !childCount ? void 0 : Plugin.React.createElement(Entity_2.VisibilityControl, { entity: entity }));
                        //<RemoveEntityControl entity={entity} />
                    };
                    Entity.prototype.renderFlat = function () {
                        var node = this.node;
                        var children = [];
                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
                            var c = _a[_i];
                            children.push(Plugin.React.createElement(Entity, { key: c.id, node: c, tree: this.props.tree }));
                        }
                        return Plugin.React.createElement("div", { key: node.id }, children);
                    };
                    Entity.prototype.isFullyBound = function () {
                        var isFullyBound = true;
                        for (var _i = 0, _a = this.node.children; _i < _a.length; _i++) {
                            var c = _a[_i];
                            if (!c.transform.props.isBinding) {
                                isFullyBound = false;
                                break;
                            }
                        }
                        return isFullyBound && this.node.children.length === 1;
                    };
                    Entity.prototype.isOnCurrentPath = function () {
                        if (!this.ctx.currentEntity)
                            return false;
                        var n = this.ctx.currentEntity.parent;
                        var node = this.node;
                        while (n.parent !== n) {
                            if (n === node)
                                return true;
                            n = n.parent;
                        }
                        return false;
                    };
                    Entity.prototype.render = function () {
                        var _this = this;
                        var node = this.node;
                        this.renderedVersion = node.version;
                        var isRoot = node.parent === node;
                        if (this.isFullyBound())
                            return this.renderFlat();
                        var state = node.state;
                        var childCount = 0;
                        var children = [];
                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
                            var c = _a[_i];
                            if (c.isHidden)
                                continue;
                            if (!isRoot)
                                children.push(Plugin.React.createElement(Entity, { key: c.id, node: c, tree: this.props.tree }));
                            childCount++;
                        }
                        var expander;
                        if (children.length) {
                            expander = state.isCollapsed
                                ? Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', title: 'Expand', onClick: function () { return LiteMol.Bootstrap.Command.Entity.ToggleExpanded.dispatch(_this.ctx, node); }, icon: 'expand', customClass: 'lm-entity-tree-entry-toggle-group' })
                                : Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', title: 'Collapse', onClick: function () { return LiteMol.Bootstrap.Command.Entity.ToggleExpanded.dispatch(_this.ctx, node); }, icon: 'collapse', customClass: 'lm-entity-tree-entry-toggle-group' });
                        }
                        else {
                            if ( /*BEntity.isVisual(node) &&*/node.state.visibility === 0 /* Full */ && node.type.info.traits.isFocusable) {
                                expander = Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', icon: 'focus-on-visual', title: 'Focus', onClick: function () { return LiteMol.Bootstrap.Command.Entity.Focus.dispatch(_this.ctx, _this.ctx.select(node)); }, customClass: 'lm-entity-tree-entry-toggle-group' });
                            }
                        }
                        var main = Plugin.React.createElement("div", { className: 'lm-entity-tree-entry', onMouseEnter: function () { return _this.highlight(true); }, onMouseLeave: function () { return _this.highlight(false); }, onTouchStart: function () { return setTimeout(function () { return _this.highlight(true); }, 1000 / 30); }, onTouchCancel: function () { return setTimeout(function () { return _this.highlight(false); }, 1000 / 30); }, onTouchEnd: function () { return setTimeout(function () { return _this.highlight(false); }, 1000 / 30); } },
                            expander,
                            this.row(childCount));
                        return Plugin.React.createElement("div", { key: node.id, className: (isRoot ? 'lm-entity-tree-root' : '') },
                            main,
                            Plugin.React.createElement("div", { className: 'lm-entity-tree-children-wrap', style: { display: state.isCollapsed ? 'none' : 'block' } }, children));
                    };
                    return Entity;
                }(Views.ObserverView));
                var Tree = /** @class */ (function (_super) {
                    __extends(Tree, _super);
                    function Tree() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.renderedVersion = -1;
                        _this.root = void 0;
                        _this.splash = Entity_2.SplashInfo.Info();
                        return _this;
                    }
                    Tree.prototype.scrollIntoView = function (element) {
                        var node = this.root;
                        if (!node || !element)
                            return;
                        try {
                            var parent_1 = node.getBoundingClientRect();
                            var rect = element.getBoundingClientRect();
                            var scrollTop = node.scrollTop;
                            if (rect.top < parent_1.top) {
                                var d = parent_1.top - rect.top;
                                node.scrollTop = scrollTop - d;
                            }
                            else if (rect.bottom > parent_1.bottom) {
                                var d = rect.bottom - parent_1.bottom;
                                node.scrollTop = scrollTop + d;
                            }
                        }
                        catch (e) {
                        }
                    };
                    Tree.prototype.componentWillMount = function () {
                        var _this = this;
                        var node = this.controller.context.tree.root;
                        var ctx = node.tree.context;
                        //this.state.version = node.version;                            
                        this.subscribe(LiteMol.Bootstrap.Event.Tree.NodeUpdated.getStream(ctx), function (e) {
                            if (e.data === node) {
                                if (node.version !== _this.renderedVersion)
                                    _this.forceUpdate();
                            }
                        });
                    };
                    Tree.prototype.render = function () {
                        var _this = this;
                        var root = this.controller.context.tree.root;
                        this.renderedVersion = root.version;
                        var children = [];
                        for (var _i = 0, _a = root.children; _i < _a.length; _i++) {
                            var c = _a[_i];
                            if (c.isHidden)
                                continue;
                            children.push(Plugin.React.createElement(Entity, { key: c.id, node: c, tree: this }));
                        }
                        return Plugin.React.createElement("div", { className: 'lm-entity-tree', ref: function (root) { return _this.root = root; } },
                            Plugin.React.createElement(Entity, { key: root.id, node: root, tree: this }),
                            Plugin.React.createElement("div", { className: 'lm-entity-tree-children' }, children.length ? children : this.splash));
                    };
                    return Tree;
                }(Views.View));
                Entity_2.Tree = Tree;
            })(Entity = Views.Entity || (Views.Entity = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Entity;
            (function (Entity) {
                "use strict";
                Entity.Remove = function (props) { return Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { LiteMol.Bootstrap.Command.Tree.RemoveNode.dispatch(props.entity.tree.context, props.entity); props.onRemove.call(null); }, style: 'link', icon: 'remove', customClass: 'lm-remove-entity lm-btn-icon' }); };
                var Badge = /** @class */ (function (_super) {
                    __extends(Badge, _super);
                    function Badge() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Badge.prototype.shouldComponentUpdate = function (nextProps, nextState, nextContext) {
                        return this.props.type !== nextProps.type;
                    };
                    Badge.prototype.createBadge = function (name) {
                        if (!name.length)
                            return;
                        for (var i = 0; i < name.length; i++) {
                            if (name[i] === '_') {
                                return Plugin.React.createElement("span", null,
                                    name.substr(0, i),
                                    Plugin.React.createElement("sub", null, this.createBadge(name.substr(i + 1))));
                            }
                            else if (name[i] === '^') {
                                return Plugin.React.createElement("span", null,
                                    name.substr(0, i),
                                    Plugin.React.createElement("sup", null, this.createBadge(name.substr(i + 1))));
                            }
                        }
                        return name;
                    };
                    Badge.prototype.render = function () {
                        var type = this.props.type;
                        return Plugin.React.createElement("div", { className: 'lm-entity-badge lm-entity-badge-' + this.props.type.typeClass, title: type.name },
                            Plugin.React.createElement("div", null, type === LiteMol.Bootstrap.Entity.Root.info ? void 0 : this.createBadge(type.shortName)));
                    };
                    return Badge;
                }(Plugin.React.Component));
                Entity.Badge = Badge;
                var CurrentEntityControl = /** @class */ (function (_super) {
                    __extends(CurrentEntityControl, _super);
                    function CurrentEntityControl() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.state = { current: void 0 };
                        return _this;
                    }
                    CurrentEntityControl.prototype.componentWillMount = function () {
                        var _this = this;
                        _super.prototype.componentWillMount.call(this);
                        this.state.current = this.controller.context.currentEntity;
                        this.subscribe(LiteMol.Bootstrap.Event.Entity.CurrentChanged.getStream(this.controller.context), function (e) {
                            _this.setState({ current: e.data });
                        });
                    };
                    CurrentEntityControl.prototype.render = function () {
                        var _this = this;
                        if (!this.state.current) {
                            return Plugin.React.createElement("div", { className: 'lm-entity-info' },
                                Plugin.React.createElement("div", null,
                                    Plugin.React.createElement("span", null, this.controller.appName)));
                        }
                        //<div>{this.controller.appVersion}</div> 
                        var entity = this.state.current;
                        return Plugin.React.createElement("div", { className: 'lm-entity-info', title: entity.props.label + " " + (entity.props.description ? entity.props.description : '') },
                            Plugin.React.createElement("div", null,
                                Plugin.React.createElement(Badge, { type: entity.type.info }),
                                Plugin.React.createElement("span", null,
                                    entity.props.label,
                                    Plugin.React.createElement("span", null, entity.props.description)),
                                entity.parent === entity && !entity.children.length ? void 0 : Plugin.React.createElement(Entity.Remove, { entity: entity, onRemove: function () { return _this.forceUpdate(); } })));
                        //<div>{entity.props.label}<span>{entity.props.description}</span></div>             
                    };
                    return CurrentEntityControl;
                }(Views.View));
                Entity.CurrentEntityControl = CurrentEntityControl;
                var SplashInfo;
                (function (SplashInfo) {
                    SplashInfo.General = function () {
                        return Plugin.React.createElement("div", { className: 'lm-entity-splash-general' },
                            Plugin.React.createElement("div", null),
                            Plugin.React.createElement("span", { className: 'lm-icon lm-icon-info' }),
                            "The application operates on an entity tree structure that can be manipulated using the controls on the panel to the right.");
                    };
                    var ClassInfo = /** @class */ (function (_super) {
                        __extends(ClassInfo, _super);
                        function ClassInfo() {
                            var _this = _super !== null && _super.apply(this, arguments) || this;
                            _this.state = { isExpanded: false };
                            return _this;
                        }
                        //onClick={() => this.setState({isExpanded: !this.state.isExpanded} )}
                        //onMouseEnter={() => this.setState({isExpanded: true} )} onMouseLeave={() => this.setState({isExpanded: false} )}
                        ClassInfo.prototype.render = function () {
                            var _this = this;
                            return Plugin.React.createElement("div", { className: 'lm-entity-splash-class lm-entity-splash-class-' + (this.state.isExpanded ? 'expanded' : 'collapsed') },
                                Plugin.React.createElement("div", { onClick: function () { return _this.setState({ isExpanded: !_this.state.isExpanded }); } },
                                    Plugin.React.createElement("div", null),
                                    Plugin.React.createElement("div", { className: 'lm-entity-badge-' + this.props.cls }),
                                    " ",
                                    Plugin.React.createElement("span", null, this.props.cls)),
                                Plugin.React.createElement("div", null, this.props.desc));
                        };
                        return ClassInfo;
                    }(Plugin.React.Component));
                    SplashInfo.Info = function () {
                        return Plugin.React.createElement("div", { className: 'lm-entity-splash' },
                            Plugin.React.createElement(SplashInfo.General, null),
                            Plugin.React.createElement(ClassInfo, { cls: 'Root', desc: 'The root entity represents the starting point of all actions.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Action', desc: 'Represents a composition of one of more changes to the entity tree.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Data', desc: 'Low level data, for example a string or a CIF dictionary.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Object', desc: 'A more complex structure obtained from low level data. For example a molecule.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Visual', desc: 'A visual representation of an object.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Selection', desc: 'A description of a substructure of an object or a visual.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Behaviour', desc: 'Represents a dynamic behavior of the program. For example creating electron density surface when the selection changes.' }),
                            Plugin.React.createElement(ClassInfo, { cls: 'Group', desc: 'A collection of related entities.' }));
                    };
                })(SplashInfo = Entity.SplashInfo || (Entity.SplashInfo = {}));
            })(Entity = Views.Entity || (Views.Entity = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Views;
        (function (Views) {
            var Visualization;
            (function (Visualization) {
                "use strict";
                var ViewportControls = /** @class */ (function (_super) {
                    __extends(ViewportControls, _super);
                    function ViewportControls() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.state = { showSceneOptions: false, showHelp: false };
                        return _this;
                    }
                    ViewportControls.prototype.help = function () {
                        return Plugin.React.createElement("div", { className: 'lm-viewport-controls-scene-options lm-control' },
                            Plugin.React.createElement(Plugin.Controls.HelpBox, { title: 'Rotate', content: Plugin.React.createElement("div", null,
                                    Plugin.React.createElement("div", null, "Left button"),
                                    Plugin.React.createElement("div", null, "One finger touch")) }),
                            Plugin.React.createElement(Plugin.Controls.HelpBox, { title: 'Zoom', content: Plugin.React.createElement("div", null,
                                    Plugin.React.createElement("div", null, "Right button"),
                                    Plugin.React.createElement("div", null, "Pinch")) }),
                            Plugin.React.createElement(Plugin.Controls.HelpBox, { title: 'Move', content: Plugin.React.createElement("div", null,
                                    Plugin.React.createElement("div", null, "Middle button"),
                                    Plugin.React.createElement("div", null, "Two finger touch")) }),
                            Plugin.React.createElement(Plugin.Controls.HelpBox, { title: 'Slab', content: Plugin.React.createElement("div", null,
                                    Plugin.React.createElement("div", null, "Mouse wheel"),
                                    Plugin.React.createElement("div", null, "Three finger touch")) }));
                    };
                    ViewportControls.prototype.render = function () {
                        var _this = this;
                        var state = this.controller.latestState;
                        var options;
                        var layoutController = this.controller.context.layout;
                        var layoutState = layoutController.latestState;
                        if (this.state.showSceneOptions) {
                            options = Plugin.React.createElement("div", { className: 'lm-viewport-controls-scene-options lm-control' },
                                Plugin.React.createElement(Plugin.Controls.Toggle, { onChange: function (v) { return _this.controller.setState({ enableFog: v }); }, value: state.enableFog, label: 'Fog' }),
                                Plugin.React.createElement(Plugin.Controls.Slider, { label: 'FOV', min: 30, max: 90, onChange: function (v) { return _this.controller.setState({ cameraFOV: v }); }, value: state.cameraFOV }),
                                Plugin.React.createElement(Plugin.Controls.Slider, { label: 'Camera Speed', min: 1, max: 10, step: 0.01, onChange: function (v) { return _this.controller.setState({ cameraSpeed: v }); }, value: state.cameraSpeed }),
                                Plugin.React.createElement(Plugin.Controls.ToggleColorPicker, { color: state.clearColor, label: 'Background', position: 'below', onChange: function (c) { return _this.controller.setState({ clearColor: c }); } }));
                        }
                        else if (this.state.showHelp) {
                            options = this.help();
                        }
                        var controlsShown = !layoutState.hideControls;
                        return Plugin.React.createElement("div", { className: 'lm-viewport-controls', onMouseLeave: function () { return _this.setState({ showSceneOptions: false, showHelp: false }); } },
                            Plugin.React.createElement("div", { className: 'lm-viewport-controls-buttons' },
                                Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', active: this.state.showHelp, customClass: 'lm-btn-link-toggle-' + (this.state.showHelp ? 'on' : 'off'), icon: 'help-circle', onClick: function (e) { return _this.setState({ showHelp: !_this.state.showHelp, showSceneOptions: false }); }, title: 'Controls Help' }),
                                Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', active: this.state.showSceneOptions, customClass: 'lm-btn-link-toggle-' + (this.state.showSceneOptions ? 'on' : 'off'), icon: 'settings', onClick: function (e) { return _this.setState({ showSceneOptions: !_this.state.showSceneOptions, showHelp: false }); }, title: 'Scene Options' }),
                                Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', icon: 'screenshot', onClick: function (e) { return _this.controller.scene.scene.downloadScreenshot(); }, title: 'Screenshot' }),
                                Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { layoutController.update({ hideControls: controlsShown }); _this.forceUpdate(); }, icon: 'tools', title: controlsShown ? 'Hide Controls' : 'Show Controls', active: controlsShown, customClass: 'lm-btn-link-toggle-' + (controlsShown ? 'on' : 'off'), style: 'link' }),
                                Plugin.React.createElement(Plugin.Controls.Button, { onClick: function () { return layoutController.update({ isExpanded: !layoutState.isExpanded }); }, icon: 'expand-layout', title: layoutState.isExpanded ? 'Collapse' : 'Expand', active: layoutState.isExpanded, customClass: 'lm-btn-link-toggle-' + (layoutState.isExpanded ? 'on' : 'off'), style: 'link' }),
                                Plugin.React.createElement(Plugin.Controls.Button, { style: 'link', icon: 'reset-scene', onClick: function (e) { return LiteMol.Bootstrap.Command.Visual.ResetScene.dispatch(_this.controller.context, void 0); }, title: 'Reset scene' })),
                            options);
                    };
                    return ViewportControls;
                }(Views.View));
                Visualization.ViewportControls = ViewportControls;
                var HighlightInfo = /** @class */ (function (_super) {
                    __extends(HighlightInfo, _super);
                    function HighlightInfo() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    HighlightInfo.prototype.render = function () {
                        var state = this.controller.latestState;
                        var info = state.info;
                        if (!info.length) {
                            return Plugin.React.createElement("div", { className: 'lm-empty-control' });
                        }
                        var html = { __html: info.join(', ') };
                        return Plugin.React.createElement("div", { className: 'lm-highlight-info' },
                            Plugin.React.createElement("div", { dangerouslySetInnerHTML: html }));
                    };
                    return HighlightInfo;
                }(Views.View));
                Visualization.HighlightInfo = HighlightInfo;
                Visualization.Logo = function () {
                    return Plugin.React.createElement("div", { className: 'lm-logo' },
                        Plugin.React.createElement("div", null,
                            Plugin.React.createElement("div", null,
                                Plugin.React.createElement("div", null),
                                Plugin.React.createElement("div", { className: 'lm-logo-image' }))));
                };
                var Viewport = /** @class */ (function (_super) {
                    __extends(Viewport, _super);
                    function Viewport() {
                        var _this = _super !== null && _super.apply(this, arguments) || this;
                        _this.host3d = void 0;
                        _this.defaultBg = { r: 0, g: 0, b: 0 };
                        _this.state = { noWebGl: false, showLogo: true };
                        return _this;
                    }
                    Viewport.prototype.componentDidMount = function () {
                        if (!this.host3d || !this.controller.init(this.host3d)) {
                            this.setState({ noWebGl: true });
                        }
                        this.handleLogo();
                    };
                    Viewport.prototype.componentWillUnmount = function () {
                        _super.prototype.componentWillUnmount.call(this);
                        this.controller.destroy();
                    };
                    Viewport.prototype.renderMissing = function () {
                        return Plugin.React.createElement("div", { className: 'lm-no-webgl' },
                            Plugin.React.createElement("div", null,
                                Plugin.React.createElement("p", null,
                                    Plugin.React.createElement("b", null, "WebGL does not seem to be available.")),
                                Plugin.React.createElement("p", null, "This can be caused by an outdated browser, graphics card driver issue, or bad weather. Sometimes, just restarting the browser helps."),
                                Plugin.React.createElement("p", null,
                                    "For a list of supported browsers, refer to ",
                                    Plugin.React.createElement("a", { href: 'http://caniuse.com/#feat=webgl', target: '_blank' }, "http://caniuse.com/#feat=webgl"),
                                    ".")));
                    };
                    Viewport.prototype.handleLogo = function () {
                        var _this = this;
                        this.subscribe(LiteMol.Bootstrap.Event.Tree.NodeAdded.getStream(this.controller.context), function (e) {
                            if (LiteMol.Bootstrap.Entity.isClass(e.data, LiteMol.Bootstrap.Entity.VisualClass)) {
                                setTimeout(function () { return _this.setState({ showLogo: _this.getShowLogo() }); }, 0);
                            }
                        });
                        this.subscribe(LiteMol.Bootstrap.Event.Tree.NodeRemoved.getStream(this.controller.context), function (e) {
                            if (LiteMol.Bootstrap.Entity.isClass(e.data, LiteMol.Bootstrap.Entity.VisualClass)) {
                                setTimeout(function () { return _this.setState({ showLogo: _this.getShowLogo() }); }, 0);
                            }
                        });
                    };
                    Viewport.prototype.getShowLogo = function () {
                        try {
                            return this.controller.context.viewport.scene.models.isEmpty();
                        }
                        catch (e) {
                            return true;
                        }
                    };
                    Viewport.prototype.render = function () {
                        var _this = this;
                        if (this.state.noWebGl)
                            return this.renderMissing();
                        var color = this.controller.latestState.clearColor || this.defaultBg;
                        return Plugin.React.createElement("div", { className: 'lm-viewport', style: { backgroundColor: "rgb(" + 255 * color.r + ", " + 255 * color.g + ", " + 255 * color.b + ")" } },
                            Plugin.React.createElement("div", { ref: function (host) { return _this.host3d = host; }, className: 'lm-viewport-host3d' }),
                            this.state.showLogo ? Plugin.React.createElement(Visualization.Logo, null) : void 0,
                            Plugin.React.createElement(ViewportControls, { controller: this.controller }));
                    };
                    return Viewport;
                }(Views.View));
                Visualization.Viewport = Viewport;
            })(Visualization = Views.Visualization || (Views.Visualization = {}));
        })(Views = Plugin.Views || (Plugin.Views = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        var Components;
        (function (Components) {
            "use strict";
            function create(key, controller, view) {
                return function (t, isStatic) { return (function (ctx) { return ({
                    key: key,
                    controller: controller(ctx),
                    region: t,
                    view: view,
                    isStatic: isStatic
                }); }); };
            }
            Components.create = create;
            var AppInfo = /** @class */ (function (_super) {
                __extends(AppInfo, _super);
                function AppInfo(ctx, appName, appVersion) {
                    var _this = _super.call(this, ctx, {}) || this;
                    _this.appName = appName;
                    _this.appVersion = appVersion;
                    return _this;
                }
                return AppInfo;
            }(LiteMol.Bootstrap.Components.Component));
            Components.AppInfo = AppInfo;
            var Context;
            (function (Context) {
                Context.Log = create('Context.Log', function (s) { return new LiteMol.Bootstrap.Components.Context.Log(s); }, Plugin.Views.Context.Log);
                Context.Toast = create('Context.Toast', function (s) { return new LiteMol.Bootstrap.Components.Context.Toast(s); }, Plugin.Views.Context.Toast);
                Context.Overlay = create('Context.Overlay', function (s) { return new LiteMol.Bootstrap.Components.Context.TaskWatcher(s, 'Normal'); }, Plugin.Views.Context.Overlay);
                Context.BackgroundTasks = create('Context.BackgroundTasks', function (s) { return new LiteMol.Bootstrap.Components.Context.TaskWatcher(s, 'Background'); }, Plugin.Views.Context.BackgroundTasks);
            })(Context = Components.Context || (Components.Context = {}));
            var Transform;
            (function (Transform) {
                Transform.View = create('Transform.View', function (s) { return new LiteMol.Bootstrap.Components.Transform.View(s); }, Plugin.Views.Transform.View);
            })(Transform = Components.Transform || (Components.Transform = {}));
            var Entity;
            (function (Entity) {
                Entity.Current = function (appName, appVersion) { return create('EntityInfo', function (s) { return new AppInfo(s, appName, appVersion); }, Plugin.Views.Entity.CurrentEntityControl); };
            })(Entity = Components.Entity || (Components.Entity = {}));
            var Visualization;
            (function (Visualization) {
                Visualization.Viewport = create('Viewport', function (s) { return new LiteMol.Bootstrap.Components.Visualization.Viewport(s); }, Plugin.Views.Visualization.Viewport);
                Visualization.HighlightInfo = create('HighlightInfo', function (s) { return new LiteMol.Bootstrap.Components.Visualization.HighlightInfo(s); }, Plugin.Views.Visualization.HighlightInfo);
            })(Visualization = Components.Visualization || (Components.Visualization = {}));
        })(Components = Plugin.Components || (Plugin.Components = {}));
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        "use strict";
        Plugin.Context = LiteMol.Bootstrap.Context;
        var LayoutRegion = LiteMol.Bootstrap.Components.LayoutRegion;
        var Instance = /** @class */ (function () {
            function Instance(spec, target) {
                this.spec = spec;
                this.target = target;
                this.transformersInfo = LiteMol.Core.Utils.FastMap.create();
                this.context = new LiteMol.Bootstrap.Context(this);
                this.init();
                Plugin.ReactDOM.render(Plugin.React.createElement(this.spec.layoutView, { controller: this.context.layout }), target);
                LiteMol.Bootstrap.Command.Entity.SetCurrent.dispatch(this.context, this.context.tree.root);
            }
            Instance.prototype.compose = function () {
                for (var _i = 0, _a = Object.keys(this.spec.settings); _i < _a.length; _i++) {
                    var s = _a[_i];
                    if (!Object.prototype.hasOwnProperty.call(this.spec.settings, s))
                        continue;
                    this.context.settings.set(s, this.spec.settings[s]);
                }
                for (var _b = 0, _c = (this.spec.behaviours || []); _b < _c.length; _b++) {
                    var b = _c[_b];
                    b(this.context);
                }
                for (var _d = 0, _e = this.spec.transforms; _d < _e.length; _d++) {
                    var t = _e[_d];
                    this.context.transforms.add(t.transformer);
                    this.transformersInfo.set(t.transformer.info.id, t);
                }
            };
            Instance.prototype.prepareTargets = function () {
                var targets = LiteMol.Bootstrap.Components.makeEmptyTargets();
                var componentMap = LiteMol.Core.Utils.FastMap.create();
                for (var _i = 0, _a = this.spec.components; _i < _a.length; _i++) {
                    var cs = _a[_i];
                    var info = cs(this.context);
                    if (componentMap.has(info.key)) {
                        throw "Component with key '" + info.key + "' was already added. Fix your spec.";
                    }
                    targets[info.region].components.push(info);
                    componentMap.set(info.key, info);
                }
                if (this.spec.tree) {
                    targets[this.spec.tree.region].components.push({
                        key: 'lm-internal-tree',
                        controller: new LiteMol.Bootstrap.Components.Component(this.context, {}),
                        region: this.spec.tree.region,
                        view: this.spec.tree.view,
                        isStatic: true
                    });
                }
                targets[LayoutRegion.Main].components.push({
                    key: 'lm-internal-viewport',
                    controller: this.context.viewport,
                    region: LayoutRegion.Main,
                    view: this.spec.viewport.view,
                    isStatic: true
                });
                return targets;
            };
            Instance.prototype.getTransformerInfo = function (transformer) {
                return this.transformersInfo.get(transformer.info.id);
            };
            Instance.prototype.destroy = function () {
                this.context.dispatcher.finished();
                Plugin.ReactDOM.unmountComponentAtNode(this.target);
                this.context = void 0;
                this.spec = void 0;
                this.target = void 0;
            };
            Instance.prototype.setComponents = function (components) {
                this.spec.components = components;
                var targets = this.prepareTargets();
                this.context.layout.updateTargets(targets);
            };
            Instance.prototype.init = function () {
                this.compose();
                var targets = this.prepareTargets();
                this.context.createLayout(targets, this.target);
            };
            return Instance;
        }());
        Plugin.Instance = Instance;
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        "use strict";
        var Transformer = LiteMol.Bootstrap.Entity.Transformer;
        var DataSources;
        (function (DataSources) {
            DataSources.DownloadMolecule = Transformer.Molecule.downloadMoleculeSource({
                sourceId: 'url-molecule',
                name: 'URL',
                description: 'Download a molecule from the specified URL (if the host server supports cross domain requests).',
                defaultId: 'https://webchem.ncbr.muni.cz/CoordinateServer/1tqn/cartoon',
                urlTemplate: function (id) { return id; },
                isFullUrl: true
            });
        })(DataSources = Plugin.DataSources || (Plugin.DataSources = {}));
        var LayoutRegion = LiteMol.Bootstrap.Components.LayoutRegion;
        function getDefaultSpecification() {
            return {
                settings: {
                    'molecule.model.defaultQuery': "residues({ name: 'ALA' })",
                    'molecule.model.defaultAssemblyName': '1',
                    'molecule.coordinateStreaming.defaultId': '1jj2',
                    'molecule.coordinateStreaming.defaultServer': 'https://webchem.ncbr.muni.cz/CoordinateServer',
                    'molecule.coordinateStreaming.defaultRadius': 10,
                    'density.defaultVisualBehaviourRadius': 5
                },
                transforms: [
                    // Root transforms
                    { transformer: Transformer.Molecule.CoordinateStreaming.InitStreaming, view: Plugin.Views.Transform.Molecule.InitCoordinateStreaming, initiallyCollapsed: true },
                    { transformer: DataSources.DownloadMolecule, view: Plugin.Views.Transform.Data.WithUrlIdField, initiallyCollapsed: true },
                    { transformer: Transformer.Molecule.OpenMoleculeFromFile, view: Plugin.Views.Transform.Molecule.OpenFile, initiallyCollapsed: true },
                    { transformer: Transformer.Data.Download, view: Plugin.Views.Transform.Data.Download, initiallyCollapsed: true },
                    { transformer: Transformer.Data.OpenFile, view: Plugin.Views.Transform.Data.OpenFile, initiallyCollapsed: true },
                    // Raw data transforms
                    { transformer: Transformer.Molecule.CreateFromData, view: Plugin.Views.Transform.Molecule.CreateFromData },
                    { transformer: Transformer.Data.ParseCif, view: Plugin.Views.Transform.Empty },
                    { transformer: Transformer.Density.ParseData, view: Plugin.Views.Transform.Density.ParseData },
                    // Molecule(model) transforms
                    { transformer: Transformer.Molecule.CreateFromMmCif, view: Plugin.Views.Transform.Molecule.CreateFromMmCif },
                    { transformer: Transformer.Molecule.CreateModel, view: Plugin.Views.Transform.Molecule.CreateModel, initiallyCollapsed: true },
                    { transformer: Transformer.Molecule.CreateSelection, view: Plugin.Views.Transform.Molecule.CreateSelection, initiallyCollapsed: true },
                    { transformer: Transformer.Molecule.CreateAssembly, view: Plugin.Views.Transform.Molecule.CreateAssembly, initiallyCollapsed: true },
                    { transformer: Transformer.Molecule.CreateSymmetryMates, view: Plugin.Views.Transform.Molecule.CreateSymmetryMates, initiallyCollapsed: true },
                    { transformer: Transformer.Molecule.CreateMacromoleculeVisual, view: Plugin.Views.Transform.Empty },
                    { transformer: Transformer.Molecule.CreateVisual, view: Plugin.Views.Transform.Molecule.CreateVisual },
                    // density transforms
                    { transformer: Transformer.Density.CreateVisual, view: Plugin.Views.Transform.Density.CreateVisual },
                    { transformer: Transformer.Density.CreateVisualBehaviour, view: Plugin.Views.Transform.Density.CreateVisualBehaviour },
                    // Coordinate streaming
                    { transformer: Transformer.Molecule.CoordinateStreaming.CreateBehaviour, view: Plugin.Views.Transform.Empty, initiallyCollapsed: true },
                ],
                behaviours: [
                    LiteMol.Bootstrap.Behaviour.SetEntityToCurrentWhenAdded,
                    LiteMol.Bootstrap.Behaviour.FocusCameraOnSelect,
                    LiteMol.Bootstrap.Behaviour.ApplySelectionToVisual,
                    LiteMol.Bootstrap.Behaviour.ApplyInteractivitySelection,
                    LiteMol.Bootstrap.Behaviour.UnselectElementOnRepeatedClick,
                    LiteMol.Bootstrap.Behaviour.Molecule.HighlightElementInfo,
                    LiteMol.Bootstrap.Behaviour.Molecule.DistanceToLastClickedElement,
                    LiteMol.Bootstrap.Behaviour.Molecule.ShowInteractionOnSelect(5)
                ],
                components: [
                    Plugin.Components.Visualization.HighlightInfo(LayoutRegion.Main, true),
                    Plugin.Components.Entity.Current('LiteMol', Plugin.VERSION.number)(LayoutRegion.Right, true),
                    Plugin.Components.Transform.View(LayoutRegion.Right),
                    Plugin.Components.Context.Log(LayoutRegion.Bottom, true),
                    Plugin.Components.Context.Overlay(LayoutRegion.Root),
                    Plugin.Components.Context.Toast(LayoutRegion.Main, true),
                    Plugin.Components.Context.BackgroundTasks(LayoutRegion.Main, true)
                ],
                viewport: {
                    view: Plugin.Views.Visualization.Viewport,
                    controlsView: Plugin.Views.Visualization.ViewportControls
                },
                layoutView: Plugin.Views.Layout,
                tree: {
                    region: LayoutRegion.Left,
                    view: Plugin.Views.Entity.Tree
                }
            };
        }
        Plugin.getDefaultSpecification = getDefaultSpecification;
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */
var LiteMol;
(function (LiteMol) {
    var Plugin;
    (function (Plugin) {
        "use strict";
        var Entity = LiteMol.Bootstrap.Entity;
        var Transformer = Entity.Transformer;
        var Controller = /** @class */ (function () {
            function Controller(optionsOrInstance) {
                if (optionsOrInstance.getTransformerInfo) {
                    this.ofInstace(optionsOrInstance);
                }
                else {
                    this.ofOptions(optionsOrInstance);
                }
            }
            Object.defineProperty(Controller.prototype, "instance", {
                get: function () { return this._instance; },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(Controller.prototype, "context", {
                get: function () { return this._instance.context; },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(Controller.prototype, "root", {
                get: function () { return this._instance.context.tree.root; },
                enumerable: true,
                configurable: true
            });
            /**
             * execute a command with the specified params.
             */
            Controller.prototype.command = function (cmd, params) {
                cmd.dispatch(this.context, params);
            };
            /**
             * Queries the entity state tree to select a list of entities
             * satisfying the selector.
             *
             * Equivalent to plugin.context.select(selector).
             *
             * @example
             *   selectEntities('model') // select node with ref = 'model'
             *   selectEntities(entity).subtree()
             *   selectEntities(Bootstrap.Tree.Selection.byRef('ref').ancestorOfType(Bootstrap.Entity.Molecule.Model))
             */
            Controller.prototype.selectEntities = function (selector) {
                return this.context.select(selector);
            };
            /**
             * Subscribes the specified event and returns
             * a disposable for the event.
             *
             * let sub = litemol.subscribe(...)
             * ...
             * sub.dispose(); // to stop listening
             */
            Controller.prototype.subscribe = function (event, onEvent) {
                return event.getStream(this.context).subscribe(onEvent);
            };
            /**
             * Create a transform builder.
             */
            Controller.prototype.createTransform = function () {
                return LiteMol.Bootstrap.Tree.Transform.build();
            };
            /**
             * Applies a state trasnform.
             */
            Controller.prototype.applyTransform = function (transform) {
                var ctx = this.context;
                return LiteMol.Bootstrap.Tree.Transform.apply(ctx, transform).run();
            };
            /**
             * Remove all entities.
             */
            Controller.prototype.clear = function () {
                this.command(LiteMol.Bootstrap.Command.Tree.RemoveNode, this.root);
            };
            /**
             * Set the background of the viewport from:
             *
             * HEX color in format '#rgb' or '#rrggbb'
             * or Visualization.Color instance.
             */
            Controller.prototype.setViewportBackground = function (color) {
                if (LiteMol.Visualization.Color.isColor(color)) {
                    this.command(LiteMol.Bootstrap.Command.Layout.SetViewportOptions, { clearColor: color });
                }
                else {
                    this.command(LiteMol.Bootstrap.Command.Layout.SetViewportOptions, { clearColor: LiteMol.Visualization.Color.fromHexString(color) });
                }
            };
            /**
             * Sets the state of the plugin layout.
             *
             * Expanded, show/hide controls, etc..
             */
            Controller.prototype.setLayoutState = function (state) {
                this.command(LiteMol.Bootstrap.Command.Layout.SetState, state);
            };
            /**
             * Load molecule from url or string/binary data.
             *
             * Default format is mmCIF.
             */
            Controller.prototype.loadMolecule = function (source) {
                var action = this.createTransform();
                if (!source.url && !source.data) {
                    throw new Error('Please specify either url or data');
                }
                var format = LiteMol.Core.Formats.Molecule.SupportedFormats.mmCIF;
                if (source.format) {
                    if (LiteMol.Core.Formats.FormatInfo.is(source.format)) {
                        format = source.format;
                    }
                    else {
                        var f = LiteMol.Core.Formats.FormatInfo.fromShortcut(LiteMol.Core.Formats.Molecule.SupportedFormats.All, source.format);
                        if (!f) {
                            throw new Error("'" + source.format + "' is not a supported format.");
                        }
                        format = f;
                    }
                }
                var data = source.data
                    ? action.add(this.root, Entity.Transformer.Data.FromData, { data: source.data, id: source.id })
                    : action.add(this.root, Transformer.Data.Download, { url: source.url, type: format.isBinary ? 'Binary' : 'String', id: source.id, title: 'Molecule' });
                var model = data
                    .then(Transformer.Molecule.CreateFromData, { format: format, customId: source.id }, { isBinding: true, ref: source.moleculeRef })
                    .then(Transformer.Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false, ref: source.modelRef });
                if (!source.doNotCreateVisual) {
                    model.then(Transformer.Molecule.CreateMacromoleculeVisual, { polymer: true, het: true, water: true });
                }
                return this.applyTransform(data);
            };
            /**
             * Destroys the the plugin instance.
             * The controller becomes unusable as a result.
             */
            Controller.prototype.destroy = function () {
                if (!this._instance)
                    return;
                this._instance.destroy();
                this._instance = void 0;
            };
            Controller.prototype.ofOptions = function (options) {
                var spec = options.customSpecification ? options.customSpecification : Plugin.getDefaultSpecification();
                if (!!options.allowAnalytics && !options.customSpecification) {
                    spec.behaviours.push(LiteMol.Bootstrap.Behaviour.GoogleAnalytics(options.analyticsId ? options.analyticsId : 'UA-77062725-1'));
                }
                var target;
                if (options.target instanceof HTMLElement) {
                    target = options.target;
                }
                else {
                    target = document.querySelector(options.target);
                }
                if (!target) {
                    throw new Error("options.target cannot be undefined.");
                }
                this._instance = new Plugin.Instance(spec, target);
                if (options.viewportBackground) {
                    this.setViewportBackground(options.viewportBackground);
                }
                if (options.layoutState) {
                    this.setLayoutState(options.layoutState);
                }
            };
            Controller.prototype.ofInstace = function (instance) {
                this._instance = instance;
            };
            return Controller;
        }());
        Plugin.Controller = Controller;
        function create(options) {
            return new Controller(options);
        }
        Plugin.create = create;
    })(Plugin = LiteMol.Plugin || (LiteMol.Plugin = {}));
})(LiteMol || (LiteMol = {}));
  return LiteMol;
}
if (typeof module === 'object' && typeof module.exports === 'object') {
  module.exports = __LiteMol_Plugin();
} else if (typeof define === 'function' && define.amd) {
  define(['require'], function(require) { return __LiteMol_Plugin(); })
} else {
  var __target = !!window ? window : this;
  __target.LiteMol = __LiteMol_Plugin();
}

