crowdAI/crowdai

View on GitHub
public/packs-test/application.js

Summary

Maintainability
A
0 mins
Test Coverage
/******/ (function(modules) { // webpackBootstrap
/******/     // 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] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/         // Flag the module as loaded
/******/         module.l = 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;
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, {
/******/                 configurable: false,
/******/                 enumerable: true,
/******/                 get: getter
/******/             });
/******/         }
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "/packs-test/";
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = 209);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Use invariant() to assert state which your program assumes to be true.
 *
 * Provide sprintf-style format (only %s is supported) and arguments
 * to provide information about what broke and what you were
 * expecting.
 *
 * The invariant message will be stripped in production, but the invariant
 * will remain to ensure logic does not differ in production.
 */

var validateFormat = function validateFormat(format) {};

if (true) {
  validateFormat = function validateFormat(format) {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  };
}

function invariant(condition, format, a, b, c, d, e, f) {
  validateFormat(format);

  if (!condition) {
    var error;
    if (format === undefined) {
      error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
    } else {
      var args = [a, b, c, d, e, f];
      var argIndex = 0;
      error = new Error(format.replace(/%s/g, function () {
        return args[argIndex++];
      }));
      error.name = 'Invariant Violation';
    }

    error.framesToPop = 1; // we don't care about invariant's own frame
    throw error;
  }
}

module.exports = invariant;

/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var emptyFunction = __webpack_require__(8);

/**
 * Similar to invariant but only logs a warning if the condition is not met.
 * This can be used to log issues in development environments in critical
 * paths. Removing the logging code for production environments will keep the
 * same logic and follow the same code paths.
 */

var warning = emptyFunction;

if (true) {
  var printWarning = function printWarning(format) {
    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }

    var argIndex = 0;
    var message = 'Warning: ' + format.replace(/%s/g, function () {
      return args[argIndex++];
    });
    if (typeof console !== 'undefined') {
      console.error(message);
    }
    try {
      // --- Welcome to debugging React ---
      // This error was thrown as a convenience so that you can use this stack
      // to find the callsite that caused this warning to fire.
      throw new Error(message);
    } catch (x) {}
  };

  warning = function warning(condition, format) {
    if (format === undefined) {
      throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
    }

    if (format.indexOf('Failed Composite propType: ') === 0) {
      return; // Ignore CompositeComponent proptype check.
    }

    if (!condition) {
      for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
        args[_key2 - 2] = arguments[_key2];
      }

      printWarning.apply(undefined, [format].concat(args));
    }
  };
}

module.exports = warning;

/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */


/**
 * WARNING: DO NOT manually require this module.
 * This is a replacement for `invariant(...)` used by the error code system
 * and will _only_ be required by the corresponding babel pass.
 * It always throws.
 */

function reactProdInvariant(code) {
  var argCount = arguments.length - 1;

  var message = 'Minified React error #' + code + '; visit ' + 'http://facebook.github.io/react/docs/error-decoder.html?invariant=' + code;

  for (var argIdx = 0; argIdx < argCount; argIdx++) {
    message += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]);
  }

  message += ' for the full message or use the non-minified dev environment' + ' for full errors and additional helpful warnings.';

  var error = new Error(message);
  error.name = 'Invariant Violation';
  error.framesToPop = 1; // we don't care about reactProdInvariant's own frame

  throw error;
}

module.exports = reactProdInvariant;

/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/


/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;

function toObject(val) {
    if (val === null || val === undefined) {
        throw new TypeError('Object.assign cannot be called with null or undefined');
    }

    return Object(val);
}

function shouldUseNative() {
    try {
        if (!Object.assign) {
            return false;
        }

        // Detect buggy property enumeration order in older V8 versions.

        // https://bugs.chromium.org/p/v8/issues/detail?id=4118
        var test1 = new String('abc');  // eslint-disable-line no-new-wrappers
        test1[5] = 'de';
        if (Object.getOwnPropertyNames(test1)[0] === '5') {
            return false;
        }

        // https://bugs.chromium.org/p/v8/issues/detail?id=3056
        var test2 = {};
        for (var i = 0; i < 10; i++) {
            test2['_' + String.fromCharCode(i)] = i;
        }
        var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
            return test2[n];
        });
        if (order2.join('') !== '0123456789') {
            return false;
        }

        // https://bugs.chromium.org/p/v8/issues/detail?id=3056
        var test3 = {};
        'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
            test3[letter] = letter;
        });
        if (Object.keys(Object.assign({}, test3)).join('') !==
                'abcdefghijklmnopqrst') {
            return false;
        }

        return true;
    } catch (err) {
        // We don't expect any of the above to throw, but better to be safe.
        return false;
    }
}

module.exports = shouldUseNative() ? Object.assign : function (target, source) {
    var from;
    var to = toObject(target);
    var symbols;

    for (var s = 1; s < arguments.length; s++) {
        from = Object(arguments[s]);

        for (var key in from) {
            if (hasOwnProperty.call(from, key)) {
                to[key] = from[key];
            }
        }

        if (getOwnPropertySymbols) {
            symbols = getOwnPropertySymbols(from);
            for (var i = 0; i < symbols.length; i++) {
                if (propIsEnumerable.call(from, symbols[i])) {
                    to[symbols[i]] = from[symbols[i]];
                }
            }
        }
    }

    return to;
};


/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var DOMProperty = __webpack_require__(13);
var ReactDOMComponentFlags = __webpack_require__(59);

var invariant = __webpack_require__(0);

var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
var Flags = ReactDOMComponentFlags;

var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2);

/**
 * Check if a given node should be cached.
 */
function shouldPrecacheNode(node, nodeID) {
  return node.nodeType === 1 && node.getAttribute(ATTR_NAME) === String(nodeID) || node.nodeType === 8 && node.nodeValue === ' react-text: ' + nodeID + ' ' || node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' ';
}

/**
 * Drill down (through composites and empty components) until we get a host or
 * host text component.
 *
 * This is pretty polymorphic but unavoidable with the current structure we have
 * for `_renderedChildren`.
 */
function getRenderedHostOrTextFromComponent(component) {
  var rendered;
  while (rendered = component._renderedComponent) {
    component = rendered;
  }
  return component;
}

/**
 * Populate `_hostNode` on the rendered host/text component with the given
 * DOM node. The passed `inst` can be a composite.
 */
function precacheNode(inst, node) {
  var hostInst = getRenderedHostOrTextFromComponent(inst);
  hostInst._hostNode = node;
  node[internalInstanceKey] = hostInst;
}

function uncacheNode(inst) {
  var node = inst._hostNode;
  if (node) {
    delete node[internalInstanceKey];
    inst._hostNode = null;
  }
}

/**
 * Populate `_hostNode` on each child of `inst`, assuming that the children
 * match up with the DOM (element) children of `node`.
 *
 * We cache entire levels at once to avoid an n^2 problem where we access the
 * children of a node sequentially and have to walk from the start to our target
 * node every time.
 *
 * Since we update `_renderedChildren` and the actual DOM at (slightly)
 * different times, we could race here and see a newer `_renderedChildren` than
 * the DOM nodes we see. To avoid this, ReactMultiChild calls
 * `prepareToManageChildren` before we change `_renderedChildren`, at which
 * time the container's child nodes are always cached (until it unmounts).
 */
function precacheChildNodes(inst, node) {
  if (inst._flags & Flags.hasCachedChildNodes) {
    return;
  }
  var children = inst._renderedChildren;
  var childNode = node.firstChild;
  outer: for (var name in children) {
    if (!children.hasOwnProperty(name)) {
      continue;
    }
    var childInst = children[name];
    var childID = getRenderedHostOrTextFromComponent(childInst)._domID;
    if (childID === 0) {
      // We're currently unmounting this child in ReactMultiChild; skip it.
      continue;
    }
    // We assume the child nodes are in the same order as the child instances.
    for (; childNode !== null; childNode = childNode.nextSibling) {
      if (shouldPrecacheNode(childNode, childID)) {
        precacheNode(childInst, childNode);
        continue outer;
      }
    }
    // We reached the end of the DOM children without finding an ID match.
     true ?  true ? invariant(false, 'Unable to find element with ID %s.', childID) : _prodInvariant('32', childID) : void 0;
  }
  inst._flags |= Flags.hasCachedChildNodes;
}

/**
 * Given a DOM node, return the closest ReactDOMComponent or
 * ReactDOMTextComponent instance ancestor.
 */
function getClosestInstanceFromNode(node) {
  if (node[internalInstanceKey]) {
    return node[internalInstanceKey];
  }

  // Walk up the tree until we find an ancestor whose instance we have cached.
  var parents = [];
  while (!node[internalInstanceKey]) {
    parents.push(node);
    if (node.parentNode) {
      node = node.parentNode;
    } else {
      // Top of the tree. This node must not be part of a React tree (or is
      // unmounted, potentially).
      return null;
    }
  }

  var closest;
  var inst;
  for (; node && (inst = node[internalInstanceKey]); node = parents.pop()) {
    closest = inst;
    if (parents.length) {
      precacheChildNodes(inst, node);
    }
  }

  return closest;
}

/**
 * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent
 * instance, or null if the node was not rendered by this React.
 */
function getInstanceFromNode(node) {
  var inst = getClosestInstanceFromNode(node);
  if (inst != null && inst._hostNode === node) {
    return inst;
  } else {
    return null;
  }
}

/**
 * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding
 * DOM node.
 */
function getNodeFromInstance(inst) {
  // Without this first invariant, passing a non-DOM-component triggers the next
  // invariant for a missing parent, which is super confusing.
  !(inst._hostNode !== undefined) ?  true ? invariant(false, 'getNodeFromInstance: Invalid argument.') : _prodInvariant('33') : void 0;

  if (inst._hostNode) {
    return inst._hostNode;
  }

  // Walk up the tree until we find an ancestor whose DOM node we have cached.
  var parents = [];
  while (!inst._hostNode) {
    parents.push(inst);
    !inst._hostParent ?  true ? invariant(false, 'React DOM tree root should always have a node reference.') : _prodInvariant('34') : void 0;
    inst = inst._hostParent;
  }

  // Now parents contains each ancestor that does *not* have a cached native
  // node, and `inst` is the deepest ancestor that does.
  for (; parents.length; inst = parents.pop()) {
    precacheChildNodes(inst, inst._hostNode);
  }

  return inst._hostNode;
}

var ReactDOMComponentTree = {
  getClosestInstanceFromNode: getClosestInstanceFromNode,
  getInstanceFromNode: getInstanceFromNode,
  getNodeFromInstance: getNodeFromInstance,
  precacheChildNodes: precacheChildNodes,
  precacheNode: precacheNode,
  uncacheNode: uncacheNode
};

module.exports = ReactDOMComponentTree;

/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);

/**
 * Simple, lightweight module assisting with the detection and context of
 * Worker. Helps avoid circular dependencies and allows code to reason about
 * whether or not they are in a Worker, even if they never include the main
 * `ReactWorker` dependency.
 */
var ExecutionEnvironment = {

  canUseDOM: canUseDOM,

  canUseWorkers: typeof Worker !== 'undefined',

  canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent),

  canUseViewport: canUseDOM && !!window.screen,

  isInWorker: !canUseDOM // For now, this is true - might change in the future.

};

module.exports = ExecutionEnvironment;

/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(17);

var ReactCurrentOwner = __webpack_require__(9);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

function isNative(fn) {
  // Based on isNative() from Lodash
  var funcToString = Function.prototype.toString;
  var hasOwnProperty = Object.prototype.hasOwnProperty;
  var reIsNative = RegExp('^' + funcToString
  // Take an example native function source for comparison
  .call(hasOwnProperty
  // Strip regex characters so we can use it for regex
  ).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'
  // Remove hasOwnProperty from the template to make it generic
  ).replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
  try {
    var source = funcToString.call(fn);
    return reIsNative.test(source);
  } catch (err) {
    return false;
  }
}

var canUseCollections =
// Array.from
typeof Array.from === 'function' &&
// Map
typeof Map === 'function' && isNative(Map) &&
// Map.prototype.keys
Map.prototype != null && typeof Map.prototype.keys === 'function' && isNative(Map.prototype.keys) &&
// Set
typeof Set === 'function' && isNative(Set) &&
// Set.prototype.keys
Set.prototype != null && typeof Set.prototype.keys === 'function' && isNative(Set.prototype.keys);

var setItem;
var getItem;
var removeItem;
var getItemIDs;
var addRoot;
var removeRoot;
var getRootIDs;

if (canUseCollections) {
  var itemMap = new Map();
  var rootIDSet = new Set();

  setItem = function (id, item) {
    itemMap.set(id, item);
  };
  getItem = function (id) {
    return itemMap.get(id);
  };
  removeItem = function (id) {
    itemMap['delete'](id);
  };
  getItemIDs = function () {
    return Array.from(itemMap.keys());
  };

  addRoot = function (id) {
    rootIDSet.add(id);
  };
  removeRoot = function (id) {
    rootIDSet['delete'](id);
  };
  getRootIDs = function () {
    return Array.from(rootIDSet.keys());
  };
} else {
  var itemByKey = {};
  var rootByKey = {};

  // Use non-numeric keys to prevent V8 performance issues:
  // https://github.com/facebook/react/pull/7232
  var getKeyFromID = function (id) {
    return '.' + id;
  };
  var getIDFromKey = function (key) {
    return parseInt(key.substr(1), 10);
  };

  setItem = function (id, item) {
    var key = getKeyFromID(id);
    itemByKey[key] = item;
  };
  getItem = function (id) {
    var key = getKeyFromID(id);
    return itemByKey[key];
  };
  removeItem = function (id) {
    var key = getKeyFromID(id);
    delete itemByKey[key];
  };
  getItemIDs = function () {
    return Object.keys(itemByKey).map(getIDFromKey);
  };

  addRoot = function (id) {
    var key = getKeyFromID(id);
    rootByKey[key] = true;
  };
  removeRoot = function (id) {
    var key = getKeyFromID(id);
    delete rootByKey[key];
  };
  getRootIDs = function () {
    return Object.keys(rootByKey).map(getIDFromKey);
  };
}

var unmountedIDs = [];

function purgeDeep(id) {
  var item = getItem(id);
  if (item) {
    var childIDs = item.childIDs;

    removeItem(id);
    childIDs.forEach(purgeDeep);
  }
}

function describeComponentFrame(name, source, ownerName) {
  return '\n    in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : '');
}

function getDisplayName(element) {
  if (element == null) {
    return '#empty';
  } else if (typeof element === 'string' || typeof element === 'number') {
    return '#text';
  } else if (typeof element.type === 'string') {
    return element.type;
  } else {
    return element.type.displayName || element.type.name || 'Unknown';
  }
}

function describeID(id) {
  var name = ReactComponentTreeHook.getDisplayName(id);
  var element = ReactComponentTreeHook.getElement(id);
  var ownerID = ReactComponentTreeHook.getOwnerID(id);
  var ownerName;
  if (ownerID) {
    ownerName = ReactComponentTreeHook.getDisplayName(ownerID);
  }
   true ? warning(element, 'ReactComponentTreeHook: Missing React element for debugID %s when ' + 'building stack', id) : void 0;
  return describeComponentFrame(name, element && element._source, ownerName);
}

var ReactComponentTreeHook = {
  onSetChildren: function (id, nextChildIDs) {
    var item = getItem(id);
    !item ?  true ? invariant(false, 'Item must have been set') : _prodInvariant('144') : void 0;
    item.childIDs = nextChildIDs;

    for (var i = 0; i < nextChildIDs.length; i++) {
      var nextChildID = nextChildIDs[i];
      var nextChild = getItem(nextChildID);
      !nextChild ?  true ? invariant(false, 'Expected hook events to fire for the child before its parent includes it in onSetChildren().') : _prodInvariant('140') : void 0;
      !(nextChild.childIDs != null || typeof nextChild.element !== 'object' || nextChild.element == null) ?  true ? invariant(false, 'Expected onSetChildren() to fire for a container child before its parent includes it in onSetChildren().') : _prodInvariant('141') : void 0;
      !nextChild.isMounted ?  true ? invariant(false, 'Expected onMountComponent() to fire for the child before its parent includes it in onSetChildren().') : _prodInvariant('71') : void 0;
      if (nextChild.parentID == null) {
        nextChild.parentID = id;
        // TODO: This shouldn't be necessary but mounting a new root during in
        // componentWillMount currently causes not-yet-mounted components to
        // be purged from our tree data so their parent id is missing.
      }
      !(nextChild.parentID === id) ?  true ? invariant(false, 'Expected onBeforeMountComponent() parent and onSetChildren() to be consistent (%s has parents %s and %s).', nextChildID, nextChild.parentID, id) : _prodInvariant('142', nextChildID, nextChild.parentID, id) : void 0;
    }
  },
  onBeforeMountComponent: function (id, element, parentID) {
    var item = {
      element: element,
      parentID: parentID,
      text: null,
      childIDs: [],
      isMounted: false,
      updateCount: 0
    };
    setItem(id, item);
  },
  onBeforeUpdateComponent: function (id, element) {
    var item = getItem(id);
    if (!item || !item.isMounted) {
      // We may end up here as a result of setState() in componentWillUnmount().
      // In this case, ignore the element.
      return;
    }
    item.element = element;
  },
  onMountComponent: function (id) {
    var item = getItem(id);
    !item ?  true ? invariant(false, 'Item must have been set') : _prodInvariant('144') : void 0;
    item.isMounted = true;
    var isRoot = item.parentID === 0;
    if (isRoot) {
      addRoot(id);
    }
  },
  onUpdateComponent: function (id) {
    var item = getItem(id);
    if (!item || !item.isMounted) {
      // We may end up here as a result of setState() in componentWillUnmount().
      // In this case, ignore the element.
      return;
    }
    item.updateCount++;
  },
  onUnmountComponent: function (id) {
    var item = getItem(id);
    if (item) {
      // We need to check if it exists.
      // `item` might not exist if it is inside an error boundary, and a sibling
      // error boundary child threw while mounting. Then this instance never
      // got a chance to mount, but it still gets an unmounting event during
      // the error boundary cleanup.
      item.isMounted = false;
      var isRoot = item.parentID === 0;
      if (isRoot) {
        removeRoot(id);
      }
    }
    unmountedIDs.push(id);
  },
  purgeUnmountedComponents: function () {
    if (ReactComponentTreeHook._preventPurging) {
      // Should only be used for testing.
      return;
    }

    for (var i = 0; i < unmountedIDs.length; i++) {
      var id = unmountedIDs[i];
      purgeDeep(id);
    }
    unmountedIDs.length = 0;
  },
  isMounted: function (id) {
    var item = getItem(id);
    return item ? item.isMounted : false;
  },
  getCurrentStackAddendum: function (topElement) {
    var info = '';
    if (topElement) {
      var name = getDisplayName(topElement);
      var owner = topElement._owner;
      info += describeComponentFrame(name, topElement._source, owner && owner.getName());
    }

    var currentOwner = ReactCurrentOwner.current;
    var id = currentOwner && currentOwner._debugID;

    info += ReactComponentTreeHook.getStackAddendumByID(id);
    return info;
  },
  getStackAddendumByID: function (id) {
    var info = '';
    while (id) {
      info += describeID(id);
      id = ReactComponentTreeHook.getParentID(id);
    }
    return info;
  },
  getChildIDs: function (id) {
    var item = getItem(id);
    return item ? item.childIDs : [];
  },
  getDisplayName: function (id) {
    var element = ReactComponentTreeHook.getElement(id);
    if (!element) {
      return null;
    }
    return getDisplayName(element);
  },
  getElement: function (id) {
    var item = getItem(id);
    return item ? item.element : null;
  },
  getOwnerID: function (id) {
    var element = ReactComponentTreeHook.getElement(id);
    if (!element || !element._owner) {
      return null;
    }
    return element._owner._debugID;
  },
  getParentID: function (id) {
    var item = getItem(id);
    return item ? item.parentID : null;
  },
  getSource: function (id) {
    var item = getItem(id);
    var element = item ? item.element : null;
    var source = element != null ? element._source : null;
    return source;
  },
  getText: function (id) {
    var element = ReactComponentTreeHook.getElement(id);
    if (typeof element === 'string') {
      return element;
    } else if (typeof element === 'number') {
      return '' + element;
    } else {
      return null;
    }
  },
  getUpdateCount: function (id) {
    var item = getItem(id);
    return item ? item.updateCount : 0;
  },


  getRootIDs: getRootIDs,
  getRegisteredIDs: getItemIDs,

  pushNonStandardWarningStack: function (isCreatingElement, currentSource) {
    if (typeof console.reactStack !== 'function') {
      return;
    }

    var stack = [];
    var currentOwner = ReactCurrentOwner.current;
    var id = currentOwner && currentOwner._debugID;

    try {
      if (isCreatingElement) {
        stack.push({
          name: id ? ReactComponentTreeHook.getDisplayName(id) : null,
          fileName: currentSource ? currentSource.fileName : null,
          lineNumber: currentSource ? currentSource.lineNumber : null
        });
      }

      while (id) {
        var element = ReactComponentTreeHook.getElement(id);
        var parentID = ReactComponentTreeHook.getParentID(id);
        var ownerID = ReactComponentTreeHook.getOwnerID(id);
        var ownerName = ownerID ? ReactComponentTreeHook.getDisplayName(ownerID) : null;
        var source = element && element._source;
        stack.push({
          name: ownerName,
          fileName: source ? source.fileName : null,
          lineNumber: source ? source.lineNumber : null
        });
        id = parentID;
      }
    } catch (err) {
      // Internal state is messed up.
      // Stop building the stack (it's just a nice to have).
    }

    console.reactStack(stack);
  },
  popNonStandardWarningStack: function () {
    if (typeof console.reactStackEnd !== 'function') {
      return;
    }
    console.reactStackEnd();
  }
};

module.exports = ReactComponentTreeHook;

/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



// Trust the developer to only use ReactInstrumentation with a __DEV__ check

var debugTool = null;

if (true) {
  var ReactDebugTool = __webpack_require__(115);
  debugTool = ReactDebugTool;
}

module.exports = { debugTool: debugTool };

/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */

function makeEmptyFunction(arg) {
  return function () {
    return arg;
  };
}

/**
 * This function accepts and discards inputs; it has no side effects. This is
 * primarily useful idiomatically for overridable function endpoints which
 * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
 */
var emptyFunction = function emptyFunction() {};

emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function () {
  return this;
};
emptyFunction.thatReturnsArgument = function (arg) {
  return arg;
};

module.exports = emptyFunction;

/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/**
 * Keeps track of the current owner.
 *
 * The current owner is the component who should own any components that are
 * currently being constructed.
 */
var ReactCurrentOwner = {
  /**
   * @internal
   * @type {ReactComponent}
   */
  current: null
};

module.exports = ReactCurrentOwner;

/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var CallbackQueue = __webpack_require__(63);
var PooledClass = __webpack_require__(15);
var ReactFeatureFlags = __webpack_require__(64);
var ReactReconciler = __webpack_require__(18);
var Transaction = __webpack_require__(29);

var invariant = __webpack_require__(0);

var dirtyComponents = [];
var updateBatchNumber = 0;
var asapCallbackQueue = CallbackQueue.getPooled();
var asapEnqueued = false;

var batchingStrategy = null;

function ensureInjected() {
  !(ReactUpdates.ReactReconcileTransaction && batchingStrategy) ?  true ? invariant(false, 'ReactUpdates: must inject a reconcile transaction class and batching strategy') : _prodInvariant('123') : void 0;
}

var NESTED_UPDATES = {
  initialize: function () {
    this.dirtyComponentsLength = dirtyComponents.length;
  },
  close: function () {
    if (this.dirtyComponentsLength !== dirtyComponents.length) {
      // Additional updates were enqueued by componentDidUpdate handlers or
      // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
      // these new updates so that if A's componentDidUpdate calls setState on
      // B, B will update before the callback A's updater provided when calling
      // setState.
      dirtyComponents.splice(0, this.dirtyComponentsLength);
      flushBatchedUpdates();
    } else {
      dirtyComponents.length = 0;
    }
  }
};

var UPDATE_QUEUEING = {
  initialize: function () {
    this.callbackQueue.reset();
  },
  close: function () {
    this.callbackQueue.notifyAll();
  }
};

var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];

function ReactUpdatesFlushTransaction() {
  this.reinitializeTransaction();
  this.dirtyComponentsLength = null;
  this.callbackQueue = CallbackQueue.getPooled();
  this.reconcileTransaction = ReactUpdates.ReactReconcileTransaction.getPooled(
  /* useCreateElement */true);
}

_assign(ReactUpdatesFlushTransaction.prototype, Transaction, {
  getTransactionWrappers: function () {
    return TRANSACTION_WRAPPERS;
  },

  destructor: function () {
    this.dirtyComponentsLength = null;
    CallbackQueue.release(this.callbackQueue);
    this.callbackQueue = null;
    ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
    this.reconcileTransaction = null;
  },

  perform: function (method, scope, a) {
    // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
    // with this transaction's wrappers around it.
    return Transaction.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, method, scope, a);
  }
});

PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);

function batchedUpdates(callback, a, b, c, d, e) {
  ensureInjected();
  return batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
}

/**
 * Array comparator for ReactComponents by mount ordering.
 *
 * @param {ReactComponent} c1 first component you're comparing
 * @param {ReactComponent} c2 second component you're comparing
 * @return {number} Return value usable by Array.prototype.sort().
 */
function mountOrderComparator(c1, c2) {
  return c1._mountOrder - c2._mountOrder;
}

function runBatchedUpdates(transaction) {
  var len = transaction.dirtyComponentsLength;
  !(len === dirtyComponents.length) ?  true ? invariant(false, 'Expected flush transaction\'s stored dirty-components length (%s) to match dirty-components array length (%s).', len, dirtyComponents.length) : _prodInvariant('124', len, dirtyComponents.length) : void 0;

  // Since reconciling a component higher in the owner hierarchy usually (not
  // always -- see shouldComponentUpdate()) will reconcile children, reconcile
  // them before their children by sorting the array.
  dirtyComponents.sort(mountOrderComparator);

  // Any updates enqueued while reconciling must be performed after this entire
  // batch. Otherwise, if dirtyComponents is [A, B] where A has children B and
  // C, B could update twice in a single batch if C's render enqueues an update
  // to B (since B would have already updated, we should skip it, and the only
  // way we can know to do so is by checking the batch counter).
  updateBatchNumber++;

  for (var i = 0; i < len; i++) {
    // If a component is unmounted before pending changes apply, it will still
    // be here, but we assume that it has cleared its _pendingCallbacks and
    // that performUpdateIfNecessary is a noop.
    var component = dirtyComponents[i];

    // If performUpdateIfNecessary happens to enqueue any new updates, we
    // shouldn't execute the callbacks until the next render happens, so
    // stash the callbacks first
    var callbacks = component._pendingCallbacks;
    component._pendingCallbacks = null;

    var markerName;
    if (ReactFeatureFlags.logTopLevelRenders) {
      var namedComponent = component;
      // Duck type TopLevelWrapper. This is probably always true.
      if (component._currentElement.type.isReactTopLevelWrapper) {
        namedComponent = component._renderedComponent;
      }
      markerName = 'React update: ' + namedComponent.getName();
      console.time(markerName);
    }

    ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction, updateBatchNumber);

    if (markerName) {
      console.timeEnd(markerName);
    }

    if (callbacks) {
      for (var j = 0; j < callbacks.length; j++) {
        transaction.callbackQueue.enqueue(callbacks[j], component.getPublicInstance());
      }
    }
  }
}

var flushBatchedUpdates = function () {
  // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
  // array and perform any updates enqueued by mount-ready handlers (i.e.,
  // componentDidUpdate) but we need to check here too in order to catch
  // updates enqueued by setState callbacks and asap calls.
  while (dirtyComponents.length || asapEnqueued) {
    if (dirtyComponents.length) {
      var transaction = ReactUpdatesFlushTransaction.getPooled();
      transaction.perform(runBatchedUpdates, null, transaction);
      ReactUpdatesFlushTransaction.release(transaction);
    }

    if (asapEnqueued) {
      asapEnqueued = false;
      var queue = asapCallbackQueue;
      asapCallbackQueue = CallbackQueue.getPooled();
      queue.notifyAll();
      CallbackQueue.release(queue);
    }
  }
};

/**
 * Mark a component as needing a rerender, adding an optional callback to a
 * list of functions which will be executed once the rerender occurs.
 */
function enqueueUpdate(component) {
  ensureInjected();

  // Various parts of our code (such as ReactCompositeComponent's
  // _renderValidatedComponent) assume that calls to render aren't nested;
  // verify that that's the case. (This is called by each top-level update
  // function, like setState, forceUpdate, etc.; creation and
  // destruction of top-level components is guarded in ReactMount.)

  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

/**
 * Enqueue a callback to be run at the end of the current batching cycle. Throws
 * if no updates are currently being performed.
 */
function asap(callback, context) {
  invariant(batchingStrategy.isBatchingUpdates, "ReactUpdates.asap: Can't enqueue an asap callback in a context where" + 'updates are not being batched.');
  asapCallbackQueue.enqueue(callback, context);
  asapEnqueued = true;
}

var ReactUpdatesInjection = {
  injectReconcileTransaction: function (ReconcileTransaction) {
    !ReconcileTransaction ?  true ? invariant(false, 'ReactUpdates: must provide a reconcile transaction class') : _prodInvariant('126') : void 0;
    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
  },

  injectBatchingStrategy: function (_batchingStrategy) {
    !_batchingStrategy ?  true ? invariant(false, 'ReactUpdates: must provide a batching strategy') : _prodInvariant('127') : void 0;
    !(typeof _batchingStrategy.batchedUpdates === 'function') ?  true ? invariant(false, 'ReactUpdates: must provide a batchedUpdates() function') : _prodInvariant('128') : void 0;
    !(typeof _batchingStrategy.isBatchingUpdates === 'boolean') ?  true ? invariant(false, 'ReactUpdates: must provide an isBatchingUpdates boolean attribute') : _prodInvariant('129') : void 0;
    batchingStrategy = _batchingStrategy;
  }
};

var ReactUpdates = {
  /**
   * React references `ReactReconcileTransaction` using this property in order
   * to allow dependency injection.
   *
   * @internal
   */
  ReactReconcileTransaction: null,

  batchedUpdates: batchedUpdates,
  enqueueUpdate: enqueueUpdate,
  flushBatchedUpdates: flushBatchedUpdates,
  injection: ReactUpdatesInjection,
  asap: asap
};

module.exports = ReactUpdates;

/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


module.exports = __webpack_require__(16);


/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var PooledClass = __webpack_require__(15);

var emptyFunction = __webpack_require__(8);
var warning = __webpack_require__(1);

var didWarnForAddedNewProperty = false;
var isProxySupported = typeof Proxy === 'function';

var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances'];

/**
 * @interface Event
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var EventInterface = {
  type: null,
  target: null,
  // currentTarget is set when dispatching; no use in copying it here
  currentTarget: emptyFunction.thatReturnsNull,
  eventPhase: null,
  bubbles: null,
  cancelable: null,
  timeStamp: function (event) {
    return event.timeStamp || Date.now();
  },
  defaultPrevented: null,
  isTrusted: null
};

/**
 * Synthetic events are dispatched by event plugins, typically in response to a
 * top-level event delegation handler.
 *
 * These systems should generally use pooling to reduce the frequency of garbage
 * collection. The system should check `isPersistent` to determine whether the
 * event should be released into the pool after being dispatched. Users that
 * need a persisted event should invoke `persist`.
 *
 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
 * normalizing browser quirks. Subclasses do not necessarily have to implement a
 * DOM interface; custom application-specific events can also subclass this.
 *
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {*} targetInst Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @param {DOMEventTarget} nativeEventTarget Target node.
 */
function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
  if (true) {
    // these have a getter/setter for warnings
    delete this.nativeEvent;
    delete this.preventDefault;
    delete this.stopPropagation;
  }

  this.dispatchConfig = dispatchConfig;
  this._targetInst = targetInst;
  this.nativeEvent = nativeEvent;

  var Interface = this.constructor.Interface;
  for (var propName in Interface) {
    if (!Interface.hasOwnProperty(propName)) {
      continue;
    }
    if (true) {
      delete this[propName]; // this has a getter/setter for warnings
    }
    var normalize = Interface[propName];
    if (normalize) {
      this[propName] = normalize(nativeEvent);
    } else {
      if (propName === 'target') {
        this.target = nativeEventTarget;
      } else {
        this[propName] = nativeEvent[propName];
      }
    }
  }

  var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false;
  if (defaultPrevented) {
    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
  } else {
    this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
  }
  this.isPropagationStopped = emptyFunction.thatReturnsFalse;
  return this;
}

_assign(SyntheticEvent.prototype, {
  preventDefault: function () {
    this.defaultPrevented = true;
    var event = this.nativeEvent;
    if (!event) {
      return;
    }

    if (event.preventDefault) {
      event.preventDefault();
      // eslint-disable-next-line valid-typeof
    } else if (typeof event.returnValue !== 'unknown') {
      event.returnValue = false;
    }
    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
  },

  stopPropagation: function () {
    var event = this.nativeEvent;
    if (!event) {
      return;
    }

    if (event.stopPropagation) {
      event.stopPropagation();
      // eslint-disable-next-line valid-typeof
    } else if (typeof event.cancelBubble !== 'unknown') {
      // The ChangeEventPlugin registers a "propertychange" event for
      // IE. This event does not support bubbling or cancelling, and
      // any references to cancelBubble throw "Member not found".  A
      // typeof check of "unknown" circumvents this issue (and is also
      // IE specific).
      event.cancelBubble = true;
    }

    this.isPropagationStopped = emptyFunction.thatReturnsTrue;
  },

  /**
   * We release all dispatched `SyntheticEvent`s after each event loop, adding
   * them back into the pool. This allows a way to hold onto a reference that
   * won't be added back into the pool.
   */
  persist: function () {
    this.isPersistent = emptyFunction.thatReturnsTrue;
  },

  /**
   * Checks if this event should be released back into the pool.
   *
   * @return {boolean} True if this should not be released, false otherwise.
   */
  isPersistent: emptyFunction.thatReturnsFalse,

  /**
   * `PooledClass` looks for `destructor` on each instance it releases.
   */
  destructor: function () {
    var Interface = this.constructor.Interface;
    for (var propName in Interface) {
      if (true) {
        Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName]));
      } else {
        this[propName] = null;
      }
    }
    for (var i = 0; i < shouldBeReleasedProperties.length; i++) {
      this[shouldBeReleasedProperties[i]] = null;
    }
    if (true) {
      Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null));
      Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction));
      Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction));
    }
  }
});

SyntheticEvent.Interface = EventInterface;

/**
 * Helper to reduce boilerplate when creating subclasses.
 *
 * @param {function} Class
 * @param {?object} Interface
 */
SyntheticEvent.augmentClass = function (Class, Interface) {
  var Super = this;

  var E = function () {};
  E.prototype = Super.prototype;
  var prototype = new E();

  _assign(prototype, Class.prototype);
  Class.prototype = prototype;
  Class.prototype.constructor = Class;

  Class.Interface = _assign({}, Super.Interface, Interface);
  Class.augmentClass = Super.augmentClass;

  PooledClass.addPoolingTo(Class, PooledClass.fourArgumentPooler);
};

/** Proxying after everything set on SyntheticEvent
  * to resolve Proxy issue on some WebKit browsers
  * in which some Event properties are set to undefined (GH#10010)
  */
if (true) {
  if (isProxySupported) {
    /*eslint-disable no-func-assign */
    SyntheticEvent = new Proxy(SyntheticEvent, {
      construct: function (target, args) {
        return this.apply(target, Object.create(target.prototype), args);
      },
      apply: function (constructor, that, args) {
        return new Proxy(constructor.apply(that, args), {
          set: function (target, prop, value) {
            if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) {
               true ? warning(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.') : void 0;
              didWarnForAddedNewProperty = true;
            }
            target[prop] = value;
            return true;
          }
        });
      }
    });
    /*eslint-enable no-func-assign */
  }
}

PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler);

module.exports = SyntheticEvent;

/**
  * Helper to nullify syntheticEvent instance properties when destructing
  *
  * @param {object} SyntheticEvent
  * @param {String} propName
  * @return {object} defineProperty object
  */
function getPooledWarningPropertyDefinition(propName, getVal) {
  var isFunction = typeof getVal === 'function';
  return {
    configurable: true,
    set: set,
    get: get
  };

  function set(val) {
    var action = isFunction ? 'setting the method' : 'setting the property';
    warn(action, 'This is effectively a no-op');
    return val;
  }

  function get() {
    var action = isFunction ? 'accessing the method' : 'accessing the property';
    var result = isFunction ? 'This is a no-op function' : 'This is set to null';
    warn(action, result);
    return getVal;
  }

  function warn(action, result) {
    var warningCondition = false;
     true ? warning(warningCondition, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result) : void 0;
  }
}

/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

function checkMask(value, bitmask) {
  return (value & bitmask) === bitmask;
}

var DOMPropertyInjection = {
  /**
   * Mapping from normalized, camelcased property names to a configuration that
   * specifies how the associated DOM property should be accessed or rendered.
   */
  MUST_USE_PROPERTY: 0x1,
  HAS_BOOLEAN_VALUE: 0x4,
  HAS_NUMERIC_VALUE: 0x8,
  HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,
  HAS_OVERLOADED_BOOLEAN_VALUE: 0x20,

  /**
   * Inject some specialized knowledge about the DOM. This takes a config object
   * with the following properties:
   *
   * isCustomAttribute: function that given an attribute name will return true
   * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
   * attributes where it's impossible to enumerate all of the possible
   * attribute names,
   *
   * Properties: object mapping DOM property name to one of the
   * DOMPropertyInjection constants or null. If your attribute isn't in here,
   * it won't get written to the DOM.
   *
   * DOMAttributeNames: object mapping React attribute name to the DOM
   * attribute name. Attribute names not specified use the **lowercase**
   * normalized name.
   *
   * DOMAttributeNamespaces: object mapping React attribute name to the DOM
   * attribute namespace URL. (Attribute names not specified use no namespace.)
   *
   * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
   * Property names not specified use the normalized name.
   *
   * DOMMutationMethods: Properties that require special mutation methods. If
   * `value` is undefined, the mutation method should unset the property.
   *
   * @param {object} domPropertyConfig the config as described above.
   */
  injectDOMPropertyConfig: function (domPropertyConfig) {
    var Injection = DOMPropertyInjection;
    var Properties = domPropertyConfig.Properties || {};
    var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {};
    var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
    var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
    var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};

    if (domPropertyConfig.isCustomAttribute) {
      DOMProperty._isCustomAttributeFunctions.push(domPropertyConfig.isCustomAttribute);
    }

    for (var propName in Properties) {
      !!DOMProperty.properties.hasOwnProperty(propName) ?  true ? invariant(false, 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property \'%s\' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.', propName) : _prodInvariant('48', propName) : void 0;

      var lowerCased = propName.toLowerCase();
      var propConfig = Properties[propName];

      var propertyInfo = {
        attributeName: lowerCased,
        attributeNamespace: null,
        propertyName: propName,
        mutationMethod: null,

        mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
        hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
        hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE),
        hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE),
        hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE)
      };
      !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ?  true ? invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s', propName) : _prodInvariant('50', propName) : void 0;

      if (true) {
        DOMProperty.getPossibleStandardName[lowerCased] = propName;
      }

      if (DOMAttributeNames.hasOwnProperty(propName)) {
        var attributeName = DOMAttributeNames[propName];
        propertyInfo.attributeName = attributeName;
        if (true) {
          DOMProperty.getPossibleStandardName[attributeName] = propName;
        }
      }

      if (DOMAttributeNamespaces.hasOwnProperty(propName)) {
        propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName];
      }

      if (DOMPropertyNames.hasOwnProperty(propName)) {
        propertyInfo.propertyName = DOMPropertyNames[propName];
      }

      if (DOMMutationMethods.hasOwnProperty(propName)) {
        propertyInfo.mutationMethod = DOMMutationMethods[propName];
      }

      DOMProperty.properties[propName] = propertyInfo;
    }
  }
};

/* eslint-disable max-len */
var ATTRIBUTE_NAME_START_CHAR = ':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';
/* eslint-enable max-len */

/**
 * DOMProperty exports lookup objects that can be used like functions:
 *
 *   > DOMProperty.isValid['id']
 *   true
 *   > DOMProperty.isValid['foobar']
 *   undefined
 *
 * Although this may be confusing, it performs better in general.
 *
 * @see http://jsperf.com/key-exists
 * @see http://jsperf.com/key-missing
 */
var DOMProperty = {
  ID_ATTRIBUTE_NAME: 'data-reactid',
  ROOT_ATTRIBUTE_NAME: 'data-reactroot',

  ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
  ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',

  /**
   * Map from property "standard name" to an object with info about how to set
   * the property in the DOM. Each object contains:
   *
   * attributeName:
   *   Used when rendering markup or with `*Attribute()`.
   * attributeNamespace
   * propertyName:
   *   Used on DOM node instances. (This includes properties that mutate due to
   *   external factors.)
   * mutationMethod:
   *   If non-null, used instead of the property or `setAttribute()` after
   *   initial render.
   * mustUseProperty:
   *   Whether the property must be accessed and mutated as an object property.
   * hasBooleanValue:
   *   Whether the property should be removed when set to a falsey value.
   * hasNumericValue:
   *   Whether the property must be numeric or parse as a numeric and should be
   *   removed when set to a falsey value.
   * hasPositiveNumericValue:
   *   Whether the property must be positive numeric or parse as a positive
   *   numeric and should be removed when set to a falsey value.
   * hasOverloadedBooleanValue:
   *   Whether the property can be used as a flag as well as with a value.
   *   Removed when strictly equal to false; present without a value when
   *   strictly equal to true; present with a value otherwise.
   */
  properties: {},

  /**
   * Mapping from lowercase property names to the properly cased version, used
   * to warn in the case of missing properties. Available only in __DEV__.
   *
   * autofocus is predefined, because adding it to the property whitelist
   * causes unintended side effects.
   *
   * @type {Object}
   */
  getPossibleStandardName:  true ? { autofocus: 'autoFocus' } : null,

  /**
   * All of the isCustomAttribute() functions that have been injected.
   */
  _isCustomAttributeFunctions: [],

  /**
   * Checks whether a property name is a custom attribute.
   * @method
   */
  isCustomAttribute: function (attributeName) {
    for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
      var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
      if (isCustomAttributeFn(attributeName)) {
        return true;
      }
    }
    return false;
  },

  injection: DOMPropertyInjection
};

module.exports = DOMProperty;

/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var ReactCurrentOwner = __webpack_require__(9);

var warning = __webpack_require__(1);
var canDefineProperty = __webpack_require__(26);
var hasOwnProperty = Object.prototype.hasOwnProperty;

var REACT_ELEMENT_TYPE = __webpack_require__(54);

var RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true
};

var specialPropKeyWarningShown, specialPropRefWarningShown;

function hasValidRef(config) {
  if (true) {
    if (hasOwnProperty.call(config, 'ref')) {
      var getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.ref !== undefined;
}

function hasValidKey(config) {
  if (true) {
    if (hasOwnProperty.call(config, 'key')) {
      var getter = Object.getOwnPropertyDescriptor(config, 'key').get;
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.key !== undefined;
}

function defineKeyPropWarningGetter(props, displayName) {
  var warnAboutAccessingKey = function () {
    if (!specialPropKeyWarningShown) {
      specialPropKeyWarningShown = true;
       true ? warning(false, '%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName) : void 0;
    }
  };
  warnAboutAccessingKey.isReactWarning = true;
  Object.defineProperty(props, 'key', {
    get: warnAboutAccessingKey,
    configurable: true
  });
}

function defineRefPropWarningGetter(props, displayName) {
  var warnAboutAccessingRef = function () {
    if (!specialPropRefWarningShown) {
      specialPropRefWarningShown = true;
       true ? warning(false, '%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName) : void 0;
    }
  };
  warnAboutAccessingRef.isReactWarning = true;
  Object.defineProperty(props, 'ref', {
    get: warnAboutAccessingRef,
    configurable: true
  });
}

/**
 * Factory method to create a new React element. This no longer adheres to
 * the class pattern, so do not use new to call it. Also, no instanceof check
 * will work. Instead test $$typeof field against Symbol.for('react.element') to check
 * if something is a React Element.
 *
 * @param {*} type
 * @param {*} key
 * @param {string|object} ref
 * @param {*} self A *temporary* helper to detect places where `this` is
 * different from the `owner` when React.createElement is called, so that we
 * can warn. We want to get rid of owner and replace string `ref`s with arrow
 * functions, and as long as `this` and owner are the same, there will be no
 * change in behavior.
 * @param {*} source An annotation object (added by a transpiler or otherwise)
 * indicating filename, line number, and/or other information.
 * @param {*} owner
 * @param {*} props
 * @internal
 */
var ReactElement = function (type, key, ref, self, source, owner, props) {
  var element = {
    // This tag allow us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    _owner: owner
  };

  if (true) {
    // The validation flag is currently mutative. We put it on
    // an external backing store so that we can freeze the whole object.
    // This can be replaced with a WeakMap once they are implemented in
    // commonly used development environments.
    element._store = {};

    // To make comparing ReactElements easier for testing purposes, we make
    // the validation flag non-enumerable (where possible, which should
    // include every environment we run tests in), so the test framework
    // ignores it.
    if (canDefineProperty) {
      Object.defineProperty(element._store, 'validated', {
        configurable: false,
        enumerable: false,
        writable: true,
        value: false
      });
      // self and source are DEV only properties.
      Object.defineProperty(element, '_self', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: self
      });
      // Two elements created in two different places should be considered
      // equal for testing purposes and therefore we hide it from enumeration.
      Object.defineProperty(element, '_source', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: source
      });
    } else {
      element._store.validated = false;
      element._self = self;
      element._source = source;
    }
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

/**
 * Create and return a new ReactElement of the given type.
 * See https://facebook.github.io/react/docs/top-level-api.html#react.createelement
 */
ReactElement.createElement = function (type, config, children) {
  var propName;

  // Reserved names are extracted
  var props = {};

  var key = null;
  var ref = null;
  var self = null;
  var source = null;

  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // Remaining properties are added to a new props object
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    if (true) {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (true) {
    if (key || ref) {
      if (typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE) {
        var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
        if (key) {
          defineKeyPropWarningGetter(props, displayName);
        }
        if (ref) {
          defineRefPropWarningGetter(props, displayName);
        }
      }
    }
  }
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};

/**
 * Return a function that produces ReactElements of a given type.
 * See https://facebook.github.io/react/docs/top-level-api.html#react.createfactory
 */
ReactElement.createFactory = function (type) {
  var factory = ReactElement.createElement.bind(null, type);
  // Expose the type on the factory and the prototype so that it can be
  // easily accessed on elements. E.g. `<Foo />.type === Foo`.
  // This should not be named `constructor` since this may not be the function
  // that created the element, and it may not even be a constructor.
  // Legacy hook TODO: Warn if this is accessed
  factory.type = type;
  return factory;
};

ReactElement.cloneAndReplaceKey = function (oldElement, newKey) {
  var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props);

  return newElement;
};

/**
 * Clone and return a new ReactElement using element as the starting point.
 * See https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement
 */
ReactElement.cloneElement = function (element, config, children) {
  var propName;

  // Original props are copied
  var props = _assign({}, element.props);

  // Reserved names are extracted
  var key = element.key;
  var ref = element.ref;
  // Self is preserved since the owner is preserved.
  var self = element._self;
  // Source is preserved since cloneElement is unlikely to be targeted by a
  // transpiler, and the original source is probably a better indicator of the
  // true owner.
  var source = element._source;

  // Owner will be preserved, unless ref is overridden
  var owner = element._owner;

  if (config != null) {
    if (hasValidRef(config)) {
      // Silently steal the ref from the parent.
      ref = config.ref;
      owner = ReactCurrentOwner.current;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    // Remaining properties override existing props
    var defaultProps;
    if (element.type && element.type.defaultProps) {
      defaultProps = element.type.defaultProps;
    }
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        if (config[propName] === undefined && defaultProps !== undefined) {
          // Resolve default props
          props[propName] = defaultProps[propName];
        } else {
          props[propName] = config[propName];
        }
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  return ReactElement(element.type, key, ref, self, source, owner, props);
};

/**
 * Verifies the object is a ReactElement.
 * See https://facebook.github.io/react/docs/top-level-api.html#react.isvalidelement
 * @param {?object} object
 * @return {boolean} True if `object` is a valid component.
 * @final
 */
ReactElement.isValidElement = function (object) {
  return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
};

module.exports = ReactElement;

/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

/**
 * Static poolers. Several custom versions for each potential number of
 * arguments. A completely generic pooler is easy to implement, but would
 * require accessing the `arguments` object. In each of these, `this` refers to
 * the Class itself, not an instance. If any others are needed, simply add them
 * here, or in their own files.
 */
var oneArgumentPooler = function (copyFieldsFrom) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, copyFieldsFrom);
    return instance;
  } else {
    return new Klass(copyFieldsFrom);
  }
};

var twoArgumentPooler = function (a1, a2) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2);
    return instance;
  } else {
    return new Klass(a1, a2);
  }
};

var threeArgumentPooler = function (a1, a2, a3) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3);
    return instance;
  } else {
    return new Klass(a1, a2, a3);
  }
};

var fourArgumentPooler = function (a1, a2, a3, a4) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3, a4);
    return instance;
  } else {
    return new Klass(a1, a2, a3, a4);
  }
};

var standardReleaser = function (instance) {
  var Klass = this;
  !(instance instanceof Klass) ?  true ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
  instance.destructor();
  if (Klass.instancePool.length < Klass.poolSize) {
    Klass.instancePool.push(instance);
  }
};

var DEFAULT_POOL_SIZE = 10;
var DEFAULT_POOLER = oneArgumentPooler;

/**
 * Augments `CopyConstructor` to be a poolable class, augmenting only the class
 * itself (statically) not adding any prototypical fields. Any CopyConstructor
 * you give this may have a `poolSize` property, and will look for a
 * prototypical `destructor` on instances.
 *
 * @param {Function} CopyConstructor Constructor that can be used to reset.
 * @param {Function} pooler Customizable pooler.
 */
var addPoolingTo = function (CopyConstructor, pooler) {
  // Casting as any so that flow ignores the actual implementation and trusts
  // it to match the type we declared
  var NewKlass = CopyConstructor;
  NewKlass.instancePool = [];
  NewKlass.getPooled = pooler || DEFAULT_POOLER;
  if (!NewKlass.poolSize) {
    NewKlass.poolSize = DEFAULT_POOL_SIZE;
  }
  NewKlass.release = standardReleaser;
  return NewKlass;
};

var PooledClass = {
  addPoolingTo: addPoolingTo,
  oneArgumentPooler: oneArgumentPooler,
  twoArgumentPooler: twoArgumentPooler,
  threeArgumentPooler: threeArgumentPooler,
  fourArgumentPooler: fourArgumentPooler
};

module.exports = PooledClass;

/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var ReactBaseClasses = __webpack_require__(52);
var ReactChildren = __webpack_require__(90);
var ReactDOMFactories = __webpack_require__(94);
var ReactElement = __webpack_require__(14);
var ReactPropTypes = __webpack_require__(98);
var ReactVersion = __webpack_require__(100);

var createReactClass = __webpack_require__(101);
var onlyChild = __webpack_require__(103);

var createElement = ReactElement.createElement;
var createFactory = ReactElement.createFactory;
var cloneElement = ReactElement.cloneElement;

if (true) {
  var lowPriorityWarning = __webpack_require__(35);
  var canDefineProperty = __webpack_require__(26);
  var ReactElementValidator = __webpack_require__(56);
  var didWarnPropTypesDeprecated = false;
  createElement = ReactElementValidator.createElement;
  createFactory = ReactElementValidator.createFactory;
  cloneElement = ReactElementValidator.cloneElement;
}

var __spread = _assign;
var createMixin = function (mixin) {
  return mixin;
};

if (true) {
  var warnedForSpread = false;
  var warnedForCreateMixin = false;
  __spread = function () {
    lowPriorityWarning(warnedForSpread, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See https://fb.me/react-spread-deprecation for more details.');
    warnedForSpread = true;
    return _assign.apply(null, arguments);
  };

  createMixin = function (mixin) {
    lowPriorityWarning(warnedForCreateMixin, 'React.createMixin is deprecated and should not be used. ' + 'In React v16.0, it will be removed. ' + 'You can use this mixin directly instead. ' + 'See https://fb.me/createmixin-was-never-implemented for more info.');
    warnedForCreateMixin = true;
    return mixin;
  };
}

var React = {
  // Modern

  Children: {
    map: ReactChildren.map,
    forEach: ReactChildren.forEach,
    count: ReactChildren.count,
    toArray: ReactChildren.toArray,
    only: onlyChild
  },

  Component: ReactBaseClasses.Component,
  PureComponent: ReactBaseClasses.PureComponent,

  createElement: createElement,
  cloneElement: cloneElement,
  isValidElement: ReactElement.isValidElement,

  // Classic

  PropTypes: ReactPropTypes,
  createClass: createReactClass,
  createFactory: createFactory,
  createMixin: createMixin,

  // This looks DOM specific but these are actually isomorphic helpers
  // since they are just generating DOM strings.
  DOM: ReactDOMFactories,

  version: ReactVersion,

  // Deprecated hook for JSX spread, don't use this for anything.
  __spread: __spread
};

if (true) {
  var warnedForCreateClass = false;
  if (canDefineProperty) {
    Object.defineProperty(React, 'PropTypes', {
      get: function () {
        lowPriorityWarning(didWarnPropTypesDeprecated, 'Accessing PropTypes via the main React package is deprecated,' + ' and will be removed in  React v16.0.' + ' Use the latest available v15.* prop-types package from npm instead.' + ' For info on usage, compatibility, migration and more, see ' + 'https://fb.me/prop-types-docs');
        didWarnPropTypesDeprecated = true;
        return ReactPropTypes;
      }
    });

    Object.defineProperty(React, 'createClass', {
      get: function () {
        lowPriorityWarning(warnedForCreateClass, 'Accessing createClass via the main React package is deprecated,' + ' and will be removed in React v16.0.' + " Use a plain JavaScript class instead. If you're not yet " + 'ready to migrate, create-react-class v15.* is available ' + 'on npm as a temporary, drop-in replacement. ' + 'For more info see https://fb.me/react-create-class');
        warnedForCreateClass = true;
        return createReactClass;
      }
    });
  }

  // React.DOM factories are deprecated. Wrap these methods so that
  // invocations of the React.DOM namespace and alert users to switch
  // to the `react-dom-factories` package.
  React.DOM = {};
  var warnedForFactories = false;
  Object.keys(ReactDOMFactories).forEach(function (factory) {
    React.DOM[factory] = function () {
      if (!warnedForFactories) {
        lowPriorityWarning(false, 'Accessing factories like React.DOM.%s has been deprecated ' + 'and will be removed in v16.0+. Use the ' + 'react-dom-factories package instead. ' + ' Version 1.0 provides a drop-in replacement.' + ' For more info, see https://fb.me/react-dom-factories', factory);
        warnedForFactories = true;
      }
      return ReactDOMFactories[factory].apply(ReactDOMFactories, arguments);
    };
  });
}

module.exports = React;

/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */


/**
 * WARNING: DO NOT manually require this module.
 * This is a replacement for `invariant(...)` used by the error code system
 * and will _only_ be required by the corresponding babel pass.
 * It always throws.
 */

function reactProdInvariant(code) {
  var argCount = arguments.length - 1;

  var message = 'Minified React error #' + code + '; visit ' + 'http://facebook.github.io/react/docs/error-decoder.html?invariant=' + code;

  for (var argIdx = 0; argIdx < argCount; argIdx++) {
    message += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]);
  }

  message += ' for the full message or use the non-minified dev environment' + ' for full errors and additional helpful warnings.';

  var error = new Error(message);
  error.name = 'Invariant Violation';
  error.framesToPop = 1; // we don't care about reactProdInvariant's own frame

  throw error;
}

module.exports = reactProdInvariant;

/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactRef = __webpack_require__(113);
var ReactInstrumentation = __webpack_require__(7);

var warning = __webpack_require__(1);

/**
 * Helper to call ReactRef.attachRefs with this composite component, split out
 * to avoid allocations in the transaction mount-ready queue.
 */
function attachRefs() {
  ReactRef.attachRefs(this, this._currentElement);
}

var ReactReconciler = {
  /**
   * Initializes the component, renders markup, and registers event listeners.
   *
   * @param {ReactComponent} internalInstance
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {?object} the containing host component instance
   * @param {?object} info about the host container
   * @return {?string} Rendered markup to be inserted into the DOM.
   * @final
   * @internal
   */
  mountComponent: function (internalInstance, transaction, hostParent, hostContainerInfo, context, parentDebugID) // 0 in production and for roots
  {
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeMountComponent(internalInstance._debugID, internalInstance._currentElement, parentDebugID);
      }
    }
    var markup = internalInstance.mountComponent(transaction, hostParent, hostContainerInfo, context, parentDebugID);
    if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
    }
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID);
      }
    }
    return markup;
  },

  /**
   * Returns a value that can be passed to
   * ReactComponentEnvironment.replaceNodeWithMarkup.
   */
  getHostNode: function (internalInstance) {
    return internalInstance.getHostNode();
  },

  /**
   * Releases any resources allocated by `mountComponent`.
   *
   * @final
   * @internal
   */
  unmountComponent: function (internalInstance, safely) {
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUnmountComponent(internalInstance._debugID);
      }
    }
    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
    internalInstance.unmountComponent(safely);
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID);
      }
    }
  },

  /**
   * Update a component using a new element.
   *
   * @param {ReactComponent} internalInstance
   * @param {ReactElement} nextElement
   * @param {ReactReconcileTransaction} transaction
   * @param {object} context
   * @internal
   */
  receiveComponent: function (internalInstance, nextElement, transaction, context) {
    var prevElement = internalInstance._currentElement;

    if (nextElement === prevElement && context === internalInstance._context) {
      // Since elements are immutable after the owner is rendered,
      // we can do a cheap identity compare here to determine if this is a
      // superfluous reconcile. It's possible for state to be mutable but such
      // change should trigger an update of the owner which would recreate
      // the element. We explicitly check for the existence of an owner since
      // it's possible for an element created outside a composite to be
      // deeply mutated and reused.

      // TODO: Bailing out early is just a perf optimization right?
      // TODO: Removing the return statement should affect correctness?
      return;
    }

    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, nextElement);
      }
    }

    var refsChanged = ReactRef.shouldUpdateRefs(prevElement, nextElement);

    if (refsChanged) {
      ReactRef.detachRefs(internalInstance, prevElement);
    }

    internalInstance.receiveComponent(nextElement, transaction, context);

    if (refsChanged && internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
    }

    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
      }
    }
  },

  /**
   * Flush any dirty changes in a component.
   *
   * @param {ReactComponent} internalInstance
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  performUpdateIfNecessary: function (internalInstance, transaction, updateBatchNumber) {
    if (internalInstance._updateBatchNumber !== updateBatchNumber) {
      // The component's enqueued batch number should always be the current
      // batch or the following one.
       true ? warning(internalInstance._updateBatchNumber == null || internalInstance._updateBatchNumber === updateBatchNumber + 1, 'performUpdateIfNecessary: Unexpected batch number (current %s, ' + 'pending %s)', updateBatchNumber, internalInstance._updateBatchNumber) : void 0;
      return;
    }
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, internalInstance._currentElement);
      }
    }
    internalInstance.performUpdateIfNecessary(transaction);
    if (true) {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
      }
    }
  }
};

module.exports = ReactReconciler;

/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMNamespaces = __webpack_require__(42);
var setInnerHTML = __webpack_require__(31);

var createMicrosoftUnsafeLocalFunction = __webpack_require__(43);
var setTextContent = __webpack_require__(68);

var ELEMENT_NODE_TYPE = 1;
var DOCUMENT_FRAGMENT_NODE_TYPE = 11;

/**
 * In IE (8-11) and Edge, appending nodes with no children is dramatically
 * faster than appending a full subtree, so we essentially queue up the
 * .appendChild calls here and apply them so each node is added to its parent
 * before any children are added.
 *
 * In other browsers, doing so is slower or neutral compared to the other order
 * (in Firefox, twice as slow) so we only do this inversion in IE.
 *
 * See https://github.com/spicyj/innerhtml-vs-createelement-vs-clonenode.
 */
var enableLazy = typeof document !== 'undefined' && typeof document.documentMode === 'number' || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && /\bEdge\/\d/.test(navigator.userAgent);

function insertTreeChildren(tree) {
  if (!enableLazy) {
    return;
  }
  var node = tree.node;
  var children = tree.children;
  if (children.length) {
    for (var i = 0; i < children.length; i++) {
      insertTreeBefore(node, children[i], null);
    }
  } else if (tree.html != null) {
    setInnerHTML(node, tree.html);
  } else if (tree.text != null) {
    setTextContent(node, tree.text);
  }
}

var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, tree, referenceNode) {
  // DocumentFragments aren't actually part of the DOM after insertion so
  // appending children won't update the DOM. We need to ensure the fragment
  // is properly populated first, breaking out of our lazy approach for just
  // this level. Also, some <object> plugins (like Flash Player) will read
  // <param> nodes immediately upon insertion into the DOM, so <object>
  // must also be populated prior to insertion into the DOM.
  if (tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || tree.node.nodeType === ELEMENT_NODE_TYPE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) {
    insertTreeChildren(tree);
    parentNode.insertBefore(tree.node, referenceNode);
  } else {
    parentNode.insertBefore(tree.node, referenceNode);
    insertTreeChildren(tree);
  }
});

function replaceChildWithTree(oldNode, newTree) {
  oldNode.parentNode.replaceChild(newTree.node, oldNode);
  insertTreeChildren(newTree);
}

function queueChild(parentTree, childTree) {
  if (enableLazy) {
    parentTree.children.push(childTree);
  } else {
    parentTree.node.appendChild(childTree.node);
  }
}

function queueHTML(tree, html) {
  if (enableLazy) {
    tree.html = html;
  } else {
    setInnerHTML(tree.node, html);
  }
}

function queueText(tree, text) {
  if (enableLazy) {
    tree.text = text;
  } else {
    setTextContent(tree.node, text);
  }
}

function toString() {
  return this.node.nodeName;
}

function DOMLazyTree(node) {
  return {
    node: node,
    children: [],
    html: null,
    text: null,
    toString: toString
  };
}

DOMLazyTree.insertTreeBefore = insertTreeBefore;
DOMLazyTree.replaceChildWithTree = replaceChildWithTree;
DOMLazyTree.queueChild = queueChild;
DOMLazyTree.queueHTML = queueHTML;
DOMLazyTree.queueText = queueText;

module.exports = DOMLazyTree;

/***/ }),
/* 20 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPluginHub = __webpack_require__(21);
var EventPluginUtils = __webpack_require__(36);

var accumulateInto = __webpack_require__(60);
var forEachAccumulated = __webpack_require__(61);
var warning = __webpack_require__(1);

var getListener = EventPluginHub.getListener;

/**
 * Some event types have a notion of different registration names for different
 * "phases" of propagation. This finds listeners by a given phase.
 */
function listenerAtPhase(inst, event, propagationPhase) {
  var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase];
  return getListener(inst, registrationName);
}

/**
 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
 * here, allows us to not have to bind or create functions for each event.
 * Mutating the event's members allows us to not have to create a wrapping
 * "dispatch" object that pairs the event with the listener.
 */
function accumulateDirectionalDispatches(inst, phase, event) {
  if (true) {
     true ? warning(inst, 'Dispatching inst must not be null') : void 0;
  }
  var listener = listenerAtPhase(inst, event, phase);
  if (listener) {
    event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
    event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
  }
}

/**
 * Collect dispatches (must be entirely collected before dispatching - see unit
 * tests). Lazily allocate the array to conserve memory.  We must loop through
 * each event and perform the traversal for each one. We cannot perform a
 * single traversal for the entire collection of events because each event may
 * have a different target.
 */
function accumulateTwoPhaseDispatchesSingle(event) {
  if (event && event.dispatchConfig.phasedRegistrationNames) {
    EventPluginUtils.traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
  }
}

/**
 * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID.
 */
function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
  if (event && event.dispatchConfig.phasedRegistrationNames) {
    var targetInst = event._targetInst;
    var parentInst = targetInst ? EventPluginUtils.getParentInstance(targetInst) : null;
    EventPluginUtils.traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event);
  }
}

/**
 * Accumulates without regard to direction, does not look for phased
 * registration names. Same as `accumulateDirectDispatchesSingle` but without
 * requiring that the `dispatchMarker` be the same as the dispatched ID.
 */
function accumulateDispatches(inst, ignoredDirection, event) {
  if (event && event.dispatchConfig.registrationName) {
    var registrationName = event.dispatchConfig.registrationName;
    var listener = getListener(inst, registrationName);
    if (listener) {
      event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
      event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
    }
  }
}

/**
 * Accumulates dispatches on an `SyntheticEvent`, but only for the
 * `dispatchMarker`.
 * @param {SyntheticEvent} event
 */
function accumulateDirectDispatchesSingle(event) {
  if (event && event.dispatchConfig.registrationName) {
    accumulateDispatches(event._targetInst, null, event);
  }
}

function accumulateTwoPhaseDispatches(events) {
  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
}

function accumulateTwoPhaseDispatchesSkipTarget(events) {
  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
}

function accumulateEnterLeaveDispatches(leave, enter, from, to) {
  EventPluginUtils.traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
}

function accumulateDirectDispatches(events) {
  forEachAccumulated(events, accumulateDirectDispatchesSingle);
}

/**
 * A small set of propagation patterns, each of which will accept a small amount
 * of information, and generate a set of "dispatch ready event objects" - which
 * are sets of events that have already been annotated with a set of dispatched
 * listener functions/ids. The API is designed this way to discourage these
 * propagation strategies from actually executing the dispatches, since we
 * always want to collect the entire set of dispatches before executing event a
 * single one.
 *
 * @constructor EventPropagators
 */
var EventPropagators = {
  accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
  accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget,
  accumulateDirectDispatches: accumulateDirectDispatches,
  accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
};

module.exports = EventPropagators;

/***/ }),
/* 21 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var EventPluginRegistry = __webpack_require__(28);
var EventPluginUtils = __webpack_require__(36);
var ReactErrorUtils = __webpack_require__(37);

var accumulateInto = __webpack_require__(60);
var forEachAccumulated = __webpack_require__(61);
var invariant = __webpack_require__(0);

/**
 * Internal store for event listeners
 */
var listenerBank = {};

/**
 * Internal queue of events that have accumulated their dispatches and are
 * waiting to have their dispatches executed.
 */
var eventQueue = null;

/**
 * Dispatches an event and releases it back into the pool, unless persistent.
 *
 * @param {?object} event Synthetic event to be dispatched.
 * @param {boolean} simulated If the event is simulated (changes exn behavior)
 * @private
 */
var executeDispatchesAndRelease = function (event, simulated) {
  if (event) {
    EventPluginUtils.executeDispatchesInOrder(event, simulated);

    if (!event.isPersistent()) {
      event.constructor.release(event);
    }
  }
};
var executeDispatchesAndReleaseSimulated = function (e) {
  return executeDispatchesAndRelease(e, true);
};
var executeDispatchesAndReleaseTopLevel = function (e) {
  return executeDispatchesAndRelease(e, false);
};

var getDictionaryKey = function (inst) {
  // Prevents V8 performance issue:
  // https://github.com/facebook/react/pull/7232
  return '.' + inst._rootNodeID;
};

function isInteractive(tag) {
  return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';
}

function shouldPreventMouseEvent(name, type, props) {
  switch (name) {
    case 'onClick':
    case 'onClickCapture':
    case 'onDoubleClick':
    case 'onDoubleClickCapture':
    case 'onMouseDown':
    case 'onMouseDownCapture':
    case 'onMouseMove':
    case 'onMouseMoveCapture':
    case 'onMouseUp':
    case 'onMouseUpCapture':
      return !!(props.disabled && isInteractive(type));
    default:
      return false;
  }
}

/**
 * This is a unified interface for event plugins to be installed and configured.
 *
 * Event plugins can implement the following properties:
 *
 *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
 *     Required. When a top-level event is fired, this method is expected to
 *     extract synthetic events that will in turn be queued and dispatched.
 *
 *   `eventTypes` {object}
 *     Optional, plugins that fire events must publish a mapping of registration
 *     names that are used to register listeners. Values of this mapping must
 *     be objects that contain `registrationName` or `phasedRegistrationNames`.
 *
 *   `executeDispatch` {function(object, function, string)}
 *     Optional, allows plugins to override how an event gets dispatched. By
 *     default, the listener is simply invoked.
 *
 * Each plugin that is injected into `EventsPluginHub` is immediately operable.
 *
 * @public
 */
var EventPluginHub = {
  /**
   * Methods for injecting dependencies.
   */
  injection: {
    /**
     * @param {array} InjectedEventPluginOrder
     * @public
     */
    injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,

    /**
     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
     */
    injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
  },

  /**
   * Stores `listener` at `listenerBank[registrationName][key]`. Is idempotent.
   *
   * @param {object} inst The instance, which is the source of events.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @param {function} listener The callback to store.
   */
  putListener: function (inst, registrationName, listener) {
    !(typeof listener === 'function') ?  true ? invariant(false, 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener) : _prodInvariant('94', registrationName, typeof listener) : void 0;

    var key = getDictionaryKey(inst);
    var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {});
    bankForRegistrationName[key] = listener;

    var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
    if (PluginModule && PluginModule.didPutListener) {
      PluginModule.didPutListener(inst, registrationName, listener);
    }
  },

  /**
   * @param {object} inst The instance, which is the source of events.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @return {?function} The stored callback.
   */
  getListener: function (inst, registrationName) {
    // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
    // live here; needs to be moved to a better place soon
    var bankForRegistrationName = listenerBank[registrationName];
    if (shouldPreventMouseEvent(registrationName, inst._currentElement.type, inst._currentElement.props)) {
      return null;
    }
    var key = getDictionaryKey(inst);
    return bankForRegistrationName && bankForRegistrationName[key];
  },

  /**
   * Deletes a listener from the registration bank.
   *
   * @param {object} inst The instance, which is the source of events.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   */
  deleteListener: function (inst, registrationName) {
    var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
    if (PluginModule && PluginModule.willDeleteListener) {
      PluginModule.willDeleteListener(inst, registrationName);
    }

    var bankForRegistrationName = listenerBank[registrationName];
    // TODO: This should never be null -- when is it?
    if (bankForRegistrationName) {
      var key = getDictionaryKey(inst);
      delete bankForRegistrationName[key];
    }
  },

  /**
   * Deletes all listeners for the DOM element with the supplied ID.
   *
   * @param {object} inst The instance, which is the source of events.
   */
  deleteAllListeners: function (inst) {
    var key = getDictionaryKey(inst);
    for (var registrationName in listenerBank) {
      if (!listenerBank.hasOwnProperty(registrationName)) {
        continue;
      }

      if (!listenerBank[registrationName][key]) {
        continue;
      }

      var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
      if (PluginModule && PluginModule.willDeleteListener) {
        PluginModule.willDeleteListener(inst, registrationName);
      }

      delete listenerBank[registrationName][key];
    }
  },

  /**
   * Allows registered plugins an opportunity to extract events from top-level
   * native browser events.
   *
   * @return {*} An accumulation of synthetic events.
   * @internal
   */
  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    var events;
    var plugins = EventPluginRegistry.plugins;
    for (var i = 0; i < plugins.length; i++) {
      // Not every plugin in the ordering may be loaded at runtime.
      var possiblePlugin = plugins[i];
      if (possiblePlugin) {
        var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget);
        if (extractedEvents) {
          events = accumulateInto(events, extractedEvents);
        }
      }
    }
    return events;
  },

  /**
   * Enqueues a synthetic event that should be dispatched when
   * `processEventQueue` is invoked.
   *
   * @param {*} events An accumulation of synthetic events.
   * @internal
   */
  enqueueEvents: function (events) {
    if (events) {
      eventQueue = accumulateInto(eventQueue, events);
    }
  },

  /**
   * Dispatches all synthetic events on the event queue.
   *
   * @internal
   */
  processEventQueue: function (simulated) {
    // Set `eventQueue` to null before processing it so that we can tell if more
    // events get enqueued while processing.
    var processingEventQueue = eventQueue;
    eventQueue = null;
    if (simulated) {
      forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseSimulated);
    } else {
      forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
    }
    !!eventQueue ?  true ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : _prodInvariant('95') : void 0;
    // This would be a good time to rethrow if any of the event handlers threw.
    ReactErrorUtils.rethrowCaughtError();
  },

  /**
   * These are needed for tests only. Do not use!
   */
  __purge: function () {
    listenerBank = {};
  },

  __getListenerBank: function () {
    return listenerBank;
  }
};

module.exports = EventPluginHub;

/***/ }),
/* 22 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

var getEventTarget = __webpack_require__(38);

/**
 * @interface UIEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var UIEventInterface = {
  view: function (event) {
    if (event.view) {
      return event.view;
    }

    var target = getEventTarget(event);
    if (target.window === target) {
      // target is a window object
      return target;
    }

    var doc = target.ownerDocument;
    // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
    if (doc) {
      return doc.defaultView || doc.parentWindow;
    } else {
      return window;
    }
  },
  detail: function (event) {
    return event.detail || 0;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticEvent}
 */
function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);

module.exports = SyntheticUIEvent;

/***/ }),
/* 23 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * `ReactInstanceMap` maintains a mapping from a public facing stateful
 * instance (key) and the internal representation (value). This allows public
 * methods to accept the user facing instance as an argument and map them back
 * to internal methods.
 */

// TODO: Replace this with ES6: var ReactInstanceMap = new Map();

var ReactInstanceMap = {
  /**
   * This API should be called `delete` but we'd have to make sure to always
   * transform these to strings for IE support. When this transform is fully
   * supported we can rename it.
   */
  remove: function (key) {
    key._reactInternalInstance = undefined;
  },

  get: function (key) {
    return key._reactInternalInstance;
  },

  has: function (key) {
    return key._reactInternalInstance !== undefined;
  },

  set: function (key, value) {
    key._reactInternalInstance = value;
  }
};

module.exports = ReactInstanceMap;

/***/ }),
/* 24 */
/***/ (function(module, exports) {

// shim for using process in browser
var process = module.exports = {};

// cached from whatever global is present so that test runners that stub it
// don't break things.  But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals.  It's inside a
// function because try/catches deoptimize in certain engines.

var cachedSetTimeout;
var cachedClearTimeout;

function defaultSetTimout() {
    throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
    throw new Error('clearTimeout has not been defined');
}
(function () {
    try {
        if (typeof setTimeout === 'function') {
            cachedSetTimeout = setTimeout;
        } else {
            cachedSetTimeout = defaultSetTimout;
        }
    } catch (e) {
        cachedSetTimeout = defaultSetTimout;
    }
    try {
        if (typeof clearTimeout === 'function') {
            cachedClearTimeout = clearTimeout;
        } else {
            cachedClearTimeout = defaultClearTimeout;
        }
    } catch (e) {
        cachedClearTimeout = defaultClearTimeout;
    }
} ())
function runTimeout(fun) {
    if (cachedSetTimeout === setTimeout) {
        //normal enviroments in sane situations
        return setTimeout(fun, 0);
    }
    // if setTimeout wasn't available but was latter defined
    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
        cachedSetTimeout = setTimeout;
        return setTimeout(fun, 0);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedSetTimeout(fun, 0);
    } catch(e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
            return cachedSetTimeout.call(null, fun, 0);
        } catch(e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
            return cachedSetTimeout.call(this, fun, 0);
        }
    }


}
function runClearTimeout(marker) {
    if (cachedClearTimeout === clearTimeout) {
        //normal enviroments in sane situations
        return clearTimeout(marker);
    }
    // if clearTimeout wasn't available but was latter defined
    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
        cachedClearTimeout = clearTimeout;
        return clearTimeout(marker);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedClearTimeout(marker);
    } catch (e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
            return cachedClearTimeout.call(null, marker);
        } catch (e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
            return cachedClearTimeout.call(this, marker);
        }
    }



}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

function cleanUpNextTick() {
    if (!draining || !currentQueue) {
        return;
    }
    draining = false;
    if (currentQueue.length) {
        queue = currentQueue.concat(queue);
    } else {
        queueIndex = -1;
    }
    if (queue.length) {
        drainQueue();
    }
}

function drainQueue() {
    if (draining) {
        return;
    }
    var timeout = runTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    runClearTimeout(timeout);
}

process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        runTimeout(drainQueue);
    }
};

// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;

process.listeners = function (name) { return [] }

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };


/***/ }),
/* 25 */
/***/ (function(module, exports, __webpack_require__) {

/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

if (true) {
  var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
    Symbol.for &&
    Symbol.for('react.element')) ||
    0xeac7;

  var isValidElement = function(object) {
    return typeof object === 'object' &&
      object !== null &&
      object.$$typeof === REACT_ELEMENT_TYPE;
  };

  // By explicitly using `prop-types` you are opting into new development behavior.
  // http://fb.me/prop-types-in-prod
  var throwOnDirectAccess = true;
  module.exports = __webpack_require__(85)(isValidElement, throwOnDirectAccess);
} else {
  // By explicitly using `prop-types` you are opting into new production behavior.
  // http://fb.me/prop-types-in-prod
  module.exports = require('./factoryWithThrowingShims')();
}


/***/ }),
/* 26 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var canDefineProperty = false;
if (true) {
  try {
    // $FlowFixMe https://github.com/facebook/flow/issues/285
    Object.defineProperty({}, 'x', { get: function () {} });
    canDefineProperty = true;
  } catch (x) {
    // IE will fail on defineProperty
  }
}

module.exports = canDefineProperty;

/***/ }),
/* 27 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var emptyObject = {};

if (true) {
  Object.freeze(emptyObject);
}

module.exports = emptyObject;

/***/ }),
/* 28 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

/**
 * Injectable ordering of event plugins.
 */
var eventPluginOrder = null;

/**
 * Injectable mapping from names to event plugin modules.
 */
var namesToPlugins = {};

/**
 * Recomputes the plugin list using the injected plugins and plugin ordering.
 *
 * @private
 */
function recomputePluginOrdering() {
  if (!eventPluginOrder) {
    // Wait until an `eventPluginOrder` is injected.
    return;
  }
  for (var pluginName in namesToPlugins) {
    var pluginModule = namesToPlugins[pluginName];
    var pluginIndex = eventPluginOrder.indexOf(pluginName);
    !(pluginIndex > -1) ?  true ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : _prodInvariant('96', pluginName) : void 0;
    if (EventPluginRegistry.plugins[pluginIndex]) {
      continue;
    }
    !pluginModule.extractEvents ?  true ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : _prodInvariant('97', pluginName) : void 0;
    EventPluginRegistry.plugins[pluginIndex] = pluginModule;
    var publishedEvents = pluginModule.eventTypes;
    for (var eventName in publishedEvents) {
      !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ?  true ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : _prodInvariant('98', eventName, pluginName) : void 0;
    }
  }
}

/**
 * Publishes an event so that it can be dispatched by the supplied plugin.
 *
 * @param {object} dispatchConfig Dispatch configuration for the event.
 * @param {object} PluginModule Plugin publishing the event.
 * @return {boolean} True if the event was successfully published.
 * @private
 */
function publishEventForPlugin(dispatchConfig, pluginModule, eventName) {
  !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ?  true ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : _prodInvariant('99', eventName) : void 0;
  EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;

  var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
  if (phasedRegistrationNames) {
    for (var phaseName in phasedRegistrationNames) {
      if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
        var phasedRegistrationName = phasedRegistrationNames[phaseName];
        publishRegistrationName(phasedRegistrationName, pluginModule, eventName);
      }
    }
    return true;
  } else if (dispatchConfig.registrationName) {
    publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName);
    return true;
  }
  return false;
}

/**
 * Publishes a registration name that is used to identify dispatched events and
 * can be used with `EventPluginHub.putListener` to register listeners.
 *
 * @param {string} registrationName Registration name to add.
 * @param {object} PluginModule Plugin publishing the event.
 * @private
 */
function publishRegistrationName(registrationName, pluginModule, eventName) {
  !!EventPluginRegistry.registrationNameModules[registrationName] ?  true ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : _prodInvariant('100', registrationName) : void 0;
  EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
  EventPluginRegistry.registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies;

  if (true) {
    var lowerCasedName = registrationName.toLowerCase();
    EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName;

    if (registrationName === 'onDoubleClick') {
      EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName;
    }
  }
}

/**
 * Registers plugins so that they can extract and dispatch events.
 *
 * @see {EventPluginHub}
 */
var EventPluginRegistry = {
  /**
   * Ordered list of injected plugins.
   */
  plugins: [],

  /**
   * Mapping from event name to dispatch config
   */
  eventNameDispatchConfigs: {},

  /**
   * Mapping from registration name to plugin module
   */
  registrationNameModules: {},

  /**
   * Mapping from registration name to event name
   */
  registrationNameDependencies: {},

  /**
   * Mapping from lowercase registration names to the properly cased version,
   * used to warn in the case of missing event handlers. Available
   * only in __DEV__.
   * @type {Object}
   */
  possibleRegistrationNames:  true ? {} : null,
  // Trust the developer to only use possibleRegistrationNames in __DEV__

  /**
   * Injects an ordering of plugins (by plugin name). This allows the ordering
   * to be decoupled from injection of the actual plugins so that ordering is
   * always deterministic regardless of packaging, on-the-fly injection, etc.
   *
   * @param {array} InjectedEventPluginOrder
   * @internal
   * @see {EventPluginHub.injection.injectEventPluginOrder}
   */
  injectEventPluginOrder: function (injectedEventPluginOrder) {
    !!eventPluginOrder ?  true ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : _prodInvariant('101') : void 0;
    // Clone the ordering so it cannot be dynamically mutated.
    eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
    recomputePluginOrdering();
  },

  /**
   * Injects plugins to be used by `EventPluginHub`. The plugin names must be
   * in the ordering injected by `injectEventPluginOrder`.
   *
   * Plugins can be injected as part of page initialization or on-the-fly.
   *
   * @param {object} injectedNamesToPlugins Map from names to plugin modules.
   * @internal
   * @see {EventPluginHub.injection.injectEventPluginsByName}
   */
  injectEventPluginsByName: function (injectedNamesToPlugins) {
    var isOrderingDirty = false;
    for (var pluginName in injectedNamesToPlugins) {
      if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
        continue;
      }
      var pluginModule = injectedNamesToPlugins[pluginName];
      if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) {
        !!namesToPlugins[pluginName] ?  true ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : _prodInvariant('102', pluginName) : void 0;
        namesToPlugins[pluginName] = pluginModule;
        isOrderingDirty = true;
      }
    }
    if (isOrderingDirty) {
      recomputePluginOrdering();
    }
  },

  /**
   * Looks up the plugin for the supplied event.
   *
   * @param {object} event A synthetic event.
   * @return {?object} The plugin that created the supplied event.
   * @internal
   */
  getPluginModuleForEvent: function (event) {
    var dispatchConfig = event.dispatchConfig;
    if (dispatchConfig.registrationName) {
      return EventPluginRegistry.registrationNameModules[dispatchConfig.registrationName] || null;
    }
    if (dispatchConfig.phasedRegistrationNames !== undefined) {
      // pulling phasedRegistrationNames out of dispatchConfig helps Flow see
      // that it is not undefined.
      var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;

      for (var phase in phasedRegistrationNames) {
        if (!phasedRegistrationNames.hasOwnProperty(phase)) {
          continue;
        }
        var pluginModule = EventPluginRegistry.registrationNameModules[phasedRegistrationNames[phase]];
        if (pluginModule) {
          return pluginModule;
        }
      }
    }
    return null;
  },

  /**
   * Exposed for unit testing.
   * @private
   */
  _resetEventPlugins: function () {
    eventPluginOrder = null;
    for (var pluginName in namesToPlugins) {
      if (namesToPlugins.hasOwnProperty(pluginName)) {
        delete namesToPlugins[pluginName];
      }
    }
    EventPluginRegistry.plugins.length = 0;

    var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
    for (var eventName in eventNameDispatchConfigs) {
      if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
        delete eventNameDispatchConfigs[eventName];
      }
    }

    var registrationNameModules = EventPluginRegistry.registrationNameModules;
    for (var registrationName in registrationNameModules) {
      if (registrationNameModules.hasOwnProperty(registrationName)) {
        delete registrationNameModules[registrationName];
      }
    }

    if (true) {
      var possibleRegistrationNames = EventPluginRegistry.possibleRegistrationNames;
      for (var lowerCasedName in possibleRegistrationNames) {
        if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) {
          delete possibleRegistrationNames[lowerCasedName];
        }
      }
    }
  }
};

module.exports = EventPluginRegistry;

/***/ }),
/* 29 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

var OBSERVED_ERROR = {};

/**
 * `Transaction` creates a black box that is able to wrap any method such that
 * certain invariants are maintained before and after the method is invoked
 * (Even if an exception is thrown while invoking the wrapped method). Whoever
 * instantiates a transaction can provide enforcers of the invariants at
 * creation time. The `Transaction` class itself will supply one additional
 * automatic invariant for you - the invariant that any transaction instance
 * should not be run while it is already being run. You would typically create a
 * single instance of a `Transaction` for reuse multiple times, that potentially
 * is used to wrap several different methods. Wrappers are extremely simple -
 * they only require implementing two methods.
 *
 * <pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>
 *
 * Use cases:
 * - Preserving the input selection ranges before/after reconciliation.
 *   Restoring selection even in the event of an unexpected error.
 * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
 *   while guaranteeing that afterwards, the event system is reactivated.
 * - Flushing a queue of collected DOM mutations to the main UI thread after a
 *   reconciliation takes place in a worker thread.
 * - Invoking any collected `componentDidUpdate` callbacks after rendering new
 *   content.
 * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
 *   to preserve the `scrollTop` (an automatic scroll aware DOM).
 * - (Future use case): Layout calculations before and after DOM updates.
 *
 * Transactional plugin API:
 * - A module that has an `initialize` method that returns any precomputation.
 * - and a `close` method that accepts the precomputation. `close` is invoked
 *   when the wrapped process is completed, or has failed.
 *
 * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
 * that implement `initialize` and `close`.
 * @return {Transaction} Single transaction for reuse in thread.
 *
 * @class Transaction
 */
var TransactionImpl = {
  /**
   * Sets up this instance so that it is prepared for collecting metrics. Does
   * so such that this setup method may be used on an instance that is already
   * initialized, in a way that does not consume additional memory upon reuse.
   * That can be useful if you decide to make your subclass of this mixin a
   * "PooledClass".
   */
  reinitializeTransaction: function () {
    this.transactionWrappers = this.getTransactionWrappers();
    if (this.wrapperInitData) {
      this.wrapperInitData.length = 0;
    } else {
      this.wrapperInitData = [];
    }
    this._isInTransaction = false;
  },

  _isInTransaction: false,

  /**
   * @abstract
   * @return {Array<TransactionWrapper>} Array of transaction wrappers.
   */
  getTransactionWrappers: null,

  isInTransaction: function () {
    return !!this._isInTransaction;
  },

  /* eslint-disable space-before-function-paren */

  /**
   * Executes the function within a safety window. Use this for the top level
   * methods that result in large amounts of computation/mutations that would
   * need to be safety checked. The optional arguments helps prevent the need
   * to bind in many cases.
   *
   * @param {function} method Member of scope to call.
   * @param {Object} scope Scope to invoke from.
   * @param {Object?=} a Argument to pass to the method.
   * @param {Object?=} b Argument to pass to the method.
   * @param {Object?=} c Argument to pass to the method.
   * @param {Object?=} d Argument to pass to the method.
   * @param {Object?=} e Argument to pass to the method.
   * @param {Object?=} f Argument to pass to the method.
   *
   * @return {*} Return value from `method`.
   */
  perform: function (method, scope, a, b, c, d, e, f) {
    /* eslint-enable space-before-function-paren */
    !!this.isInTransaction() ?  true ? invariant(false, 'Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.') : _prodInvariant('27') : void 0;
    var errorThrown;
    var ret;
    try {
      this._isInTransaction = true;
      // Catching errors makes debugging more difficult, so we start with
      // errorThrown set to true before setting it to false after calling
      // close -- if it's still set to true in the finally block, it means
      // one of these calls threw.
      errorThrown = true;
      this.initializeAll(0);
      ret = method.call(scope, a, b, c, d, e, f);
      errorThrown = false;
    } finally {
      try {
        if (errorThrown) {
          // If `method` throws, prefer to show that stack trace over any thrown
          // by invoking `closeAll`.
          try {
            this.closeAll(0);
          } catch (err) {}
        } else {
          // Since `method` didn't throw, we don't want to silence the exception
          // here.
          this.closeAll(0);
        }
      } finally {
        this._isInTransaction = false;
      }
    }
    return ret;
  },

  initializeAll: function (startIndex) {
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      try {
        // Catching errors makes debugging more difficult, so we start with the
        // OBSERVED_ERROR state before overwriting it with the real return value
        // of initialize -- if it's still set to OBSERVED_ERROR in the finally
        // block, it means wrapper.initialize threw.
        this.wrapperInitData[i] = OBSERVED_ERROR;
        this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null;
      } finally {
        if (this.wrapperInitData[i] === OBSERVED_ERROR) {
          // The initializer for wrapper i threw an error; initialize the
          // remaining wrappers but silence any exceptions from them to ensure
          // that the first error is the one to bubble up.
          try {
            this.initializeAll(i + 1);
          } catch (err) {}
        }
      }
    }
  },

  /**
   * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
   * them the respective return values of `this.transactionWrappers.init[i]`
   * (`close`rs that correspond to initializers that failed will not be
   * invoked).
   */
  closeAll: function (startIndex) {
    !this.isInTransaction() ?  true ? invariant(false, 'Transaction.closeAll(): Cannot close transaction when none are open.') : _prodInvariant('28') : void 0;
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      var initData = this.wrapperInitData[i];
      var errorThrown;
      try {
        // Catching errors makes debugging more difficult, so we start with
        // errorThrown set to true before setting it to false after calling
        // close -- if it's still set to true in the finally block, it means
        // wrapper.close threw.
        errorThrown = true;
        if (initData !== OBSERVED_ERROR && wrapper.close) {
          wrapper.close.call(this, initData);
        }
        errorThrown = false;
      } finally {
        if (errorThrown) {
          // The closer for wrapper i threw an error; close the remaining
          // wrappers but silence any exceptions from them to ensure that the
          // first error is the one to bubble up.
          try {
            this.closeAll(i + 1);
          } catch (e) {}
        }
      }
    }
    this.wrapperInitData.length = 0;
  }
};

module.exports = TransactionImpl;

/***/ }),
/* 30 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticUIEvent = __webpack_require__(22);
var ViewportMetrics = __webpack_require__(67);

var getEventModifierState = __webpack_require__(40);

/**
 * @interface MouseEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var MouseEventInterface = {
  screenX: null,
  screenY: null,
  clientX: null,
  clientY: null,
  ctrlKey: null,
  shiftKey: null,
  altKey: null,
  metaKey: null,
  getModifierState: getEventModifierState,
  button: function (event) {
    // Webkit, Firefox, IE9+
    // which:  1 2 3
    // button: 0 1 2 (standard)
    var button = event.button;
    if ('which' in event) {
      return button;
    }
    // IE<9
    // which:  undefined
    // button: 0 0 0
    // button: 1 4 2 (onmouseup)
    return button === 2 ? 2 : button === 4 ? 1 : 0;
  },
  buttons: null,
  relatedTarget: function (event) {
    return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement);
  },
  // "Proprietary" Interface.
  pageX: function (event) {
    return 'pageX' in event ? event.pageX : event.clientX + ViewportMetrics.currentScrollLeft;
  },
  pageY: function (event) {
    return 'pageY' in event ? event.pageY : event.clientY + ViewportMetrics.currentScrollTop;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);

module.exports = SyntheticMouseEvent;

/***/ }),
/* 31 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);
var DOMNamespaces = __webpack_require__(42);

var WHITESPACE_TEST = /^[ \r\n\t\f]/;
var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;

var createMicrosoftUnsafeLocalFunction = __webpack_require__(43);

// SVG temp container for IE lacking innerHTML
var reusableSVGContainer;

/**
 * Set the innerHTML property of a node, ensuring that whitespace is preserved
 * even in IE8.
 *
 * @param {DOMElement} node
 * @param {string} html
 * @internal
 */
var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) {
  // IE does not have innerHTML for SVG nodes, so instead we inject the
  // new markup in a temp node and then move the child nodes across into
  // the target node
  if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) {
    reusableSVGContainer = reusableSVGContainer || document.createElement('div');
    reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>';
    var svgNode = reusableSVGContainer.firstChild;
    while (svgNode.firstChild) {
      node.appendChild(svgNode.firstChild);
    }
  } else {
    node.innerHTML = html;
  }
});

if (ExecutionEnvironment.canUseDOM) {
  // IE8: When updating a just created node with innerHTML only leading
  // whitespace is removed. When updating an existing node with innerHTML
  // whitespace in root TextNodes is also collapsed.
  // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html

  // Feature detection; only IE8 is known to behave improperly like this.
  var testElement = document.createElement('div');
  testElement.innerHTML = ' ';
  if (testElement.innerHTML === '') {
    setInnerHTML = function (node, html) {
      // Magic theory: IE8 supposedly differentiates between added and updated
      // nodes when processing innerHTML, innerHTML on updated nodes suffers
      // from worse whitespace behavior. Re-adding a node like this triggers
      // the initial and more favorable whitespace behavior.
      // TODO: What to do on a detached node?
      if (node.parentNode) {
        node.parentNode.replaceChild(node, node);
      }

      // We also implement a workaround for non-visible tags disappearing into
      // thin air on IE8, this only happens if there is no visible text
      // in-front of the non-visible tags. Piggyback on the whitespace fix
      // and simply check if any non-visible tags appear in the source.
      if (WHITESPACE_TEST.test(html) || html[0] === '<' && NONVISIBLE_TEST.test(html)) {
        // Recover leading whitespace by temporarily prepending any character.
        // \uFEFF has the potential advantage of being zero-width/invisible.
        // UglifyJS drops U+FEFF chars when parsing, so use String.fromCharCode
        // in hopes that this is preserved even if "\uFEFF" is transformed to
        // the actual Unicode character (by Babel, for example).
        // https://github.com/mishoo/UglifyJS2/blob/v2.4.20/lib/parse.js#L216
        node.innerHTML = String.fromCharCode(0xfeff) + html;

        // deleteData leaves an empty `TextNode` which offsets the index of all
        // children. Definitely want to avoid this.
        var textNode = node.firstChild;
        if (textNode.data.length === 1) {
          node.removeChild(textNode);
        } else {
          textNode.deleteData(0, 1);
        }
      } else {
        node.innerHTML = html;
      }
    };
  }
  testElement = null;
}

module.exports = setInnerHTML;

/***/ }),
/* 32 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * Based on the escape-html library, which is used under the MIT License below:
 *
 * Copyright (c) 2012-2013 TJ Holowaychuk
 * Copyright (c) 2015 Andreas Lubbe
 * Copyright (c) 2015 Tiancheng "Timothy" Gu
 *
 * 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.
 *
 */



// code copied and modified from escape-html
/**
 * Module variables.
 * @private
 */

var matchHtmlRegExp = /["'&<>]/;

/**
 * Escape special characters in the given string of html.
 *
 * @param  {string} string The string to escape for inserting into HTML
 * @return {string}
 * @public
 */

function escapeHtml(string) {
  var str = '' + string;
  var match = matchHtmlRegExp.exec(str);

  if (!match) {
    return str;
  }

  var escape;
  var html = '';
  var index = 0;
  var lastIndex = 0;

  for (index = match.index; index < str.length; index++) {
    switch (str.charCodeAt(index)) {
      case 34:
        // "
        escape = '&quot;';
        break;
      case 38:
        // &
        escape = '&amp;';
        break;
      case 39:
        // '
        escape = '&#x27;'; // modified from escape-html; used to be '&#39'
        break;
      case 60:
        // <
        escape = '&lt;';
        break;
      case 62:
        // >
        escape = '&gt;';
        break;
      default:
        continue;
    }

    if (lastIndex !== index) {
      html += str.substring(lastIndex, index);
    }

    lastIndex = index + 1;
    html += escape;
  }

  return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}
// end code copied and modified from escape-html

/**
 * Escapes text to prevent scripting attacks.
 *
 * @param {*} text Text value to escape.
 * @return {string} An escaped string.
 */
function escapeTextContentForBrowser(text) {
  if (typeof text === 'boolean' || typeof text === 'number') {
    // this shortcircuit helps perf for types that we know will never have
    // special characters, especially given that this function is used often
    // for numeric dom ids.
    return '' + text;
  }
  return escapeHtml(text);
}

module.exports = escapeTextContentForBrowser;

/***/ }),
/* 33 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var EventPluginRegistry = __webpack_require__(28);
var ReactEventEmitterMixin = __webpack_require__(139);
var ViewportMetrics = __webpack_require__(67);

var getVendorPrefixedEventName = __webpack_require__(140);
var isEventSupported = __webpack_require__(39);

/**
 * Summary of `ReactBrowserEventEmitter` event handling:
 *
 *  - Top-level delegation is used to trap most native browser events. This
 *    may only occur in the main thread and is the responsibility of
 *    ReactEventListener, which is injected and can therefore support pluggable
 *    event sources. This is the only work that occurs in the main thread.
 *
 *  - We normalize and de-duplicate events to account for browser quirks. This
 *    may be done in the worker thread.
 *
 *  - Forward these native events (with the associated top-level type used to
 *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
 *    to extract any synthetic events.
 *
 *  - The `EventPluginHub` will then process each event by annotating them with
 *    "dispatches", a sequence of listeners and IDs that care about that event.
 *
 *  - The `EventPluginHub` then dispatches the events.
 *
 * Overview of React and the event system:
 *
 * +------------+    .
 * |    DOM     |    .
 * +------------+    .
 *       |           .
 *       v           .
 * +------------+    .
 * | ReactEvent |    .
 * |  Listener  |    .
 * +------------+    .                         +-----------+
 *       |           .               +--------+|SimpleEvent|
 *       |           .               |         |Plugin     |
 * +-----|------+    .               v         +-----------+
 * |     |      |    .    +--------------+                    +------------+
 * |     +-----------.--->|EventPluginHub|                    |    Event   |
 * |            |    .    |              |     +-----------+  | Propagators|
 * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
 * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
 * |            |    .    |              |     +-----------+  |  utilities |
 * |     +-----------.--->|              |                    +------------+
 * |     |      |    .    +--------------+
 * +-----|------+    .                ^        +-----------+
 *       |           .                |        |Enter/Leave|
 *       +           .                +-------+|Plugin     |
 * +-------------+   .                         +-----------+
 * | application |   .
 * |-------------|   .
 * |             |   .
 * |             |   .
 * +-------------+   .
 *                   .
 *    React Core     .  General Purpose Event Plugin System
 */

var hasEventPageXY;
var alreadyListeningTo = {};
var isMonitoringScrollValue = false;
var reactTopListenersCounter = 0;

// For events like 'submit' which don't consistently bubble (which we trap at a
// lower node than `document`), binding at `document` would cause duplicate
// events so we don't include them here
var topEventMapping = {
  topAbort: 'abort',
  topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
  topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
  topAnimationStart: getVendorPrefixedEventName('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: getVendorPrefixedEventName('transitionend') || 'transitionend',
  topVolumeChange: 'volumechange',
  topWaiting: 'waiting',
  topWheel: 'wheel'
};

/**
 * To ensure no conflicts with other potential React instances on the page
 */
var topListenersIDKey = '_reactListenersID' + String(Math.random()).slice(2);

function getListeningForDocument(mountAt) {
  // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
  // directly.
  if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
    mountAt[topListenersIDKey] = reactTopListenersCounter++;
    alreadyListeningTo[mountAt[topListenersIDKey]] = {};
  }
  return alreadyListeningTo[mountAt[topListenersIDKey]];
}

/**
 * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
 * example:
 *
 *   EventPluginHub.putListener('myID', 'onClick', myFunction);
 *
 * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
 *
 * @internal
 */
var ReactBrowserEventEmitter = _assign({}, ReactEventEmitterMixin, {
  /**
   * Injectable event backend
   */
  ReactEventListener: null,

  injection: {
    /**
     * @param {object} ReactEventListener
     */
    injectReactEventListener: function (ReactEventListener) {
      ReactEventListener.setHandleTopLevel(ReactBrowserEventEmitter.handleTopLevel);
      ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
    }
  },

  /**
   * Sets whether or not any created callbacks should be enabled.
   *
   * @param {boolean} enabled True if callbacks should be enabled.
   */
  setEnabled: function (enabled) {
    if (ReactBrowserEventEmitter.ReactEventListener) {
      ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
    }
  },

  /**
   * @return {boolean} True if callbacks are enabled.
   */
  isEnabled: function () {
    return !!(ReactBrowserEventEmitter.ReactEventListener && ReactBrowserEventEmitter.ReactEventListener.isEnabled());
  },

  /**
   * We listen for bubbled touch events on the document object.
   *
   * Firefox v8.01 (and possibly others) exhibited strange behavior when
   * mounting `onmousemove` events at some node that was not the document
   * element. The symptoms were that if your mouse is not moving over something
   * contained within that mount point (for example on the background) the
   * top-level listeners for `onmousemove` won't be called. However, if you
   * register the `mousemove` on the document object, then it will of course
   * catch all `mousemove`s. This along with iOS quirks, justifies restricting
   * top-level listeners to the document object only, at least for these
   * movement types of events and possibly all events.
   *
   * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
   *
   * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
   * they bubble to document.
   *
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @param {object} contentDocumentHandle Document which owns the container
   */
  listenTo: function (registrationName, contentDocumentHandle) {
    var mountAt = contentDocumentHandle;
    var isListening = getListeningForDocument(mountAt);
    var dependencies = EventPluginRegistry.registrationNameDependencies[registrationName];

    for (var i = 0; i < dependencies.length; i++) {
      var dependency = dependencies[i];
      if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
        if (dependency === 'topWheel') {
          if (isEventSupported('wheel')) {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topWheel', 'wheel', mountAt);
          } else if (isEventSupported('mousewheel')) {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topWheel', 'mousewheel', mountAt);
          } else {
            // Firefox needs to capture a different mouse scroll event.
            // @see http://www.quirksmode.org/dom/events/tests/scroll.html
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topWheel', 'DOMMouseScroll', mountAt);
          }
        } else if (dependency === 'topScroll') {
          if (isEventSupported('scroll', true)) {
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent('topScroll', 'scroll', mountAt);
          } else {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topScroll', 'scroll', ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE);
          }
        } else if (dependency === 'topFocus' || dependency === 'topBlur') {
          if (isEventSupported('focus', true)) {
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent('topFocus', 'focus', mountAt);
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent('topBlur', 'blur', mountAt);
          } else if (isEventSupported('focusin')) {
            // IE has `focusin` and `focusout` events which bubble.
            // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topFocus', 'focusin', mountAt);
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent('topBlur', 'focusout', mountAt);
          }

          // to make sure blur and focus event listeners are only attached once
          isListening.topBlur = true;
          isListening.topFocus = true;
        } else if (topEventMapping.hasOwnProperty(dependency)) {
          ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(dependency, topEventMapping[dependency], mountAt);
        }

        isListening[dependency] = true;
      }
    }
  },

  trapBubbledEvent: function (topLevelType, handlerBaseName, handle) {
    return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelType, handlerBaseName, handle);
  },

  trapCapturedEvent: function (topLevelType, handlerBaseName, handle) {
    return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelType, handlerBaseName, handle);
  },

  /**
   * Protect against document.createEvent() returning null
   * Some popup blocker extensions appear to do this:
   * https://github.com/facebook/react/issues/6887
   */
  supportsEventPageXY: function () {
    if (!document.createEvent) {
      return false;
    }
    var ev = document.createEvent('MouseEvent');
    return ev != null && 'pageX' in ev;
  },

  /**
   * Listens to window scroll and resize events. We cache scroll values so that
   * application code can access them without triggering reflows.
   *
   * ViewportMetrics is only used by SyntheticMouse/TouchEvent and only when
   * pageX/pageY isn't supported (legacy browsers).
   *
   * NOTE: Scroll events do not bubble.
   *
   * @see http://www.quirksmode.org/dom/events/scroll.html
   */
  ensureScrollValueMonitoring: function () {
    if (hasEventPageXY === undefined) {
      hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY();
    }
    if (!hasEventPageXY && !isMonitoringScrollValue) {
      var refresh = ViewportMetrics.refreshScrollValues;
      ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
      isMonitoringScrollValue = true;
    }
  }
});

module.exports = ReactBrowserEventEmitter;

/***/ }),
/* 34 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var bind = __webpack_require__(203);
var isBuffer = __webpack_require__(265);

/*global toString:true*/

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
function isArray(val) {
  return toString.call(val) === '[object Array]';
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
function isArrayBuffer(val) {
  return toString.call(val) === '[object ArrayBuffer]';
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an FormData, otherwise false
 */
function isFormData(val) {
  return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a String, otherwise false
 */
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Number, otherwise false
 */
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if the value is undefined, otherwise false
 */
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
function isDate(val) {
  return toString.call(val) === '[object Date]';
}

/**
 * Determine if a value is a File
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
function isFile(val) {
  return toString.call(val) === '[object File]';
}

/**
 * Determine if a value is a Blob
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Blob, otherwise false
 */
function isBlob(val) {
  return toString.call(val) === '[object Blob]';
}

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Function, otherwise false
 */
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Stream, otherwise false
 */
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
function isURLSearchParams(val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 * @returns {String} The String freed of excess whitespace
 */
function trim(str) {
  return str.replace(/^\s*/, '').replace(/\s*$/, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 */
function isStandardBrowserEnv() {
  if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
    return false;
  }
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined'
  );
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = merge(result[key], val);
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 * @return {Object} The resulting value of object a
 */
function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  extend: extend,
  trim: trim
};


/***/ }),
/* 35 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Forked from fbjs/warning:
 * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js
 *
 * Only change is we use console.warn instead of console.error,
 * and do nothing when 'console' is not supported.
 * This really simplifies the code.
 * ---
 * Similar to invariant but only logs a warning if the condition is not met.
 * This can be used to log issues in development environments in critical
 * paths. Removing the logging code for production environments will keep the
 * same logic and follow the same code paths.
 */

var lowPriorityWarning = function () {};

if (true) {
  var printWarning = function (format) {
    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }

    var argIndex = 0;
    var message = 'Warning: ' + format.replace(/%s/g, function () {
      return args[argIndex++];
    });
    if (typeof console !== 'undefined') {
      console.warn(message);
    }
    try {
      // --- Welcome to debugging React ---
      // This error was thrown as a convenience so that you can use this stack
      // to find the callsite that caused this warning to fire.
      throw new Error(message);
    } catch (x) {}
  };

  lowPriorityWarning = function (condition, format) {
    if (format === undefined) {
      throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
    }
    if (!condition) {
      for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
        args[_key2 - 2] = arguments[_key2];
      }

      printWarning.apply(undefined, [format].concat(args));
    }
  };
}

module.exports = lowPriorityWarning;

/***/ }),
/* 36 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactErrorUtils = __webpack_require__(37);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

/**
 * Injected dependencies:
 */

/**
 * - `ComponentTree`: [required] Module that can convert between React instances
 *   and actual node references.
 */
var ComponentTree;
var TreeTraversal;
var injection = {
  injectComponentTree: function (Injected) {
    ComponentTree = Injected;
    if (true) {
       true ? warning(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0;
    }
  },
  injectTreeTraversal: function (Injected) {
    TreeTraversal = Injected;
    if (true) {
       true ? warning(Injected && Injected.isAncestor && Injected.getLowestCommonAncestor, 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' + 'module is missing isAncestor or getLowestCommonAncestor.') : void 0;
    }
  }
};

function isEndish(topLevelType) {
  return topLevelType === 'topMouseUp' || topLevelType === 'topTouchEnd' || topLevelType === 'topTouchCancel';
}

function isMoveish(topLevelType) {
  return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
}
function isStartish(topLevelType) {
  return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
}

var validateEventDispatches;
if (true) {
  validateEventDispatches = function (event) {
    var dispatchListeners = event._dispatchListeners;
    var dispatchInstances = event._dispatchInstances;

    var listenersIsArr = Array.isArray(dispatchListeners);
    var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0;

    var instancesIsArr = Array.isArray(dispatchInstances);
    var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0;

     true ? warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : void 0;
  };
}

/**
 * Dispatch the event to the listener.
 * @param {SyntheticEvent} event SyntheticEvent to handle
 * @param {boolean} simulated If the event is simulated (changes exn behavior)
 * @param {function} listener Application-level callback
 * @param {*} inst Internal component instance
 */
function executeDispatch(event, simulated, listener, inst) {
  var type = event.type || 'unknown-event';
  event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);
  if (simulated) {
    ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event);
  } else {
    ReactErrorUtils.invokeGuardedCallback(type, listener, event);
  }
  event.currentTarget = null;
}

/**
 * Standard/simple iteration through an event's collected dispatches.
 */
function executeDispatchesInOrder(event, simulated) {
  var dispatchListeners = event._dispatchListeners;
  var dispatchInstances = event._dispatchInstances;
  if (true) {
    validateEventDispatches(event);
  }
  if (Array.isArray(dispatchListeners)) {
    for (var i = 0; i < dispatchListeners.length; i++) {
      if (event.isPropagationStopped()) {
        break;
      }
      // Listeners and Instances are two parallel arrays that are always in sync.
      executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]);
    }
  } else if (dispatchListeners) {
    executeDispatch(event, simulated, dispatchListeners, dispatchInstances);
  }
  event._dispatchListeners = null;
  event._dispatchInstances = null;
}

/**
 * Standard/simple iteration through an event's collected dispatches, but stops
 * at the first dispatch execution returning true, and returns that id.
 *
 * @return {?string} id of the first dispatch execution who's listener returns
 * true, or null if no listener returned true.
 */
function executeDispatchesInOrderStopAtTrueImpl(event) {
  var dispatchListeners = event._dispatchListeners;
  var dispatchInstances = event._dispatchInstances;
  if (true) {
    validateEventDispatches(event);
  }
  if (Array.isArray(dispatchListeners)) {
    for (var i = 0; i < dispatchListeners.length; i++) {
      if (event.isPropagationStopped()) {
        break;
      }
      // Listeners and Instances are two parallel arrays that are always in sync.
      if (dispatchListeners[i](event, dispatchInstances[i])) {
        return dispatchInstances[i];
      }
    }
  } else if (dispatchListeners) {
    if (dispatchListeners(event, dispatchInstances)) {
      return dispatchInstances;
    }
  }
  return null;
}

/**
 * @see executeDispatchesInOrderStopAtTrueImpl
 */
function executeDispatchesInOrderStopAtTrue(event) {
  var ret = executeDispatchesInOrderStopAtTrueImpl(event);
  event._dispatchInstances = null;
  event._dispatchListeners = null;
  return ret;
}

/**
 * Execution of a "direct" dispatch - there must be at most one dispatch
 * accumulated on the event or it is considered an error. It doesn't really make
 * sense for an event with multiple dispatches (bubbled) to keep track of the
 * return values at each dispatch execution, but it does tend to make sense when
 * dealing with "direct" dispatches.
 *
 * @return {*} The return value of executing the single dispatch.
 */
function executeDirectDispatch(event) {
  if (true) {
    validateEventDispatches(event);
  }
  var dispatchListener = event._dispatchListeners;
  var dispatchInstance = event._dispatchInstances;
  !!Array.isArray(dispatchListener) ?  true ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : _prodInvariant('103') : void 0;
  event.currentTarget = dispatchListener ? EventPluginUtils.getNodeFromInstance(dispatchInstance) : null;
  var res = dispatchListener ? dispatchListener(event) : null;
  event.currentTarget = null;
  event._dispatchListeners = null;
  event._dispatchInstances = null;
  return res;
}

/**
 * @param {SyntheticEvent} event
 * @return {boolean} True iff number of dispatches accumulated is greater than 0.
 */
function hasDispatches(event) {
  return !!event._dispatchListeners;
}

/**
 * General utilities that are useful in creating custom Event Plugins.
 */
var EventPluginUtils = {
  isEndish: isEndish,
  isMoveish: isMoveish,
  isStartish: isStartish,

  executeDirectDispatch: executeDirectDispatch,
  executeDispatchesInOrder: executeDispatchesInOrder,
  executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
  hasDispatches: hasDispatches,

  getInstanceFromNode: function (node) {
    return ComponentTree.getInstanceFromNode(node);
  },
  getNodeFromInstance: function (node) {
    return ComponentTree.getNodeFromInstance(node);
  },
  isAncestor: function (a, b) {
    return TreeTraversal.isAncestor(a, b);
  },
  getLowestCommonAncestor: function (a, b) {
    return TreeTraversal.getLowestCommonAncestor(a, b);
  },
  getParentInstance: function (inst) {
    return TreeTraversal.getParentInstance(inst);
  },
  traverseTwoPhase: function (target, fn, arg) {
    return TreeTraversal.traverseTwoPhase(target, fn, arg);
  },
  traverseEnterLeave: function (from, to, fn, argFrom, argTo) {
    return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo);
  },

  injection: injection
};

module.exports = EventPluginUtils;

/***/ }),
/* 37 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var caughtError = null;

/**
 * Call a function while guarding against errors that happens within it.
 *
 * @param {String} name of the guard to use for logging or debugging
 * @param {Function} func The function to invoke
 * @param {*} a First argument
 * @param {*} b Second argument
 */
function invokeGuardedCallback(name, func, a) {
  try {
    func(a);
  } catch (x) {
    if (caughtError === null) {
      caughtError = x;
    }
  }
}

var ReactErrorUtils = {
  invokeGuardedCallback: invokeGuardedCallback,

  /**
   * Invoked by ReactTestUtils.Simulate so that any errors thrown by the event
   * handler are sure to be rethrown by rethrowCaughtError.
   */
  invokeGuardedCallbackWithCatch: invokeGuardedCallback,

  /**
   * During execution of guarded functions we will capture the first error which
   * we will rethrow to be handled by the top level error handler.
   */
  rethrowCaughtError: function () {
    if (caughtError) {
      var error = caughtError;
      caughtError = null;
      throw error;
    }
  }
};

if (true) {
  /**
   * To help development we can get better devtools integration by simulating a
   * real browser event.
   */
  if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') {
    var fakeNode = document.createElement('react');
    ReactErrorUtils.invokeGuardedCallback = function (name, func, a) {
      var boundFunc = function () {
        func(a);
      };
      var evtType = 'react-' + name;
      fakeNode.addEventListener(evtType, boundFunc, false);
      var evt = document.createEvent('Event');
      evt.initEvent(evtType, false, false);
      fakeNode.dispatchEvent(evt);
      fakeNode.removeEventListener(evtType, boundFunc, false);
    };
  }
}

module.exports = ReactErrorUtils;

/***/ }),
/* 38 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Gets the target node from a native browser event by accounting for
 * inconsistencies in browser DOM APIs.
 *
 * @param {object} nativeEvent Native browser event.
 * @return {DOMEventTarget} Target node.
 */

function getEventTarget(nativeEvent) {
  var target = nativeEvent.target || nativeEvent.srcElement || window;

  // Normalize SVG <use> element events #4963
  if (target.correspondingUseElement) {
    target = target.correspondingUseElement;
  }

  // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
  // @see http://www.quirksmode.org/js/events_properties.html
  return target.nodeType === 3 ? target.parentNode : target;
}

module.exports = getEventTarget;

/***/ }),
/* 39 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);

var useHasFeature;
if (ExecutionEnvironment.canUseDOM) {
  useHasFeature = document.implementation && document.implementation.hasFeature &&
  // always returns true in newer browsers as per the standard.
  // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
  document.implementation.hasFeature('', '') !== true;
}

/**
 * Checks if an event is supported in the current execution environment.
 *
 * NOTE: This will not work correctly for non-generic events such as `change`,
 * `reset`, `load`, `error`, and `select`.
 *
 * Borrows from Modernizr.
 *
 * @param {string} eventNameSuffix Event name, e.g. "click".
 * @param {?boolean} capture Check if the capture phase is supported.
 * @return {boolean} True if the event is supported.
 * @internal
 * @license Modernizr 3.0.0pre (Custom Build) | MIT
 */
function isEventSupported(eventNameSuffix, capture) {
  if (!ExecutionEnvironment.canUseDOM || capture && !('addEventListener' in document)) {
    return false;
  }

  var eventName = 'on' + eventNameSuffix;
  var isSupported = eventName in document;

  if (!isSupported) {
    var element = document.createElement('div');
    element.setAttribute(eventName, 'return;');
    isSupported = typeof element[eventName] === 'function';
  }

  if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
    // This is the only way to test support for the `wheel` event in IE9+.
    isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
  }

  return isSupported;
}

module.exports = isEventSupported;

/***/ }),
/* 40 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Translation from modifier key to the associated property in the event.
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
 */

var modifierKeyToProp = {
  Alt: 'altKey',
  Control: 'ctrlKey',
  Meta: 'metaKey',
  Shift: 'shiftKey'
};

// IE8 does not implement getModifierState so we simply map it to the only
// modifier keys exposed by the event itself, does not support Lock-keys.
// Currently, all major browsers except Chrome seems to support Lock-keys.
function modifierStateGetter(keyArg) {
  var syntheticEvent = this;
  var nativeEvent = syntheticEvent.nativeEvent;
  if (nativeEvent.getModifierState) {
    return nativeEvent.getModifierState(keyArg);
  }
  var keyProp = modifierKeyToProp[keyArg];
  return keyProp ? !!nativeEvent[keyProp] : false;
}

function getEventModifierState(nativeEvent) {
  return modifierStateGetter;
}

module.exports = getEventModifierState;

/***/ }),
/* 41 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMLazyTree = __webpack_require__(19);
var Danger = __webpack_require__(124);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactInstrumentation = __webpack_require__(7);

var createMicrosoftUnsafeLocalFunction = __webpack_require__(43);
var setInnerHTML = __webpack_require__(31);
var setTextContent = __webpack_require__(68);

function getNodeAfter(parentNode, node) {
  // Special case for text components, which return [open, close] comments
  // from getHostNode.
  if (Array.isArray(node)) {
    node = node[1];
  }
  return node ? node.nextSibling : parentNode.firstChild;
}

/**
 * Inserts `childNode` as a child of `parentNode` at the `index`.
 *
 * @param {DOMElement} parentNode Parent node in which to insert.
 * @param {DOMElement} childNode Child node to insert.
 * @param {number} index Index at which to insert the child.
 * @internal
 */
var insertChildAt = createMicrosoftUnsafeLocalFunction(function (parentNode, childNode, referenceNode) {
  // We rely exclusively on `insertBefore(node, null)` instead of also using
  // `appendChild(node)`. (Using `undefined` is not allowed by all browsers so
  // we are careful to use `null`.)
  parentNode.insertBefore(childNode, referenceNode);
});

function insertLazyTreeChildAt(parentNode, childTree, referenceNode) {
  DOMLazyTree.insertTreeBefore(parentNode, childTree, referenceNode);
}

function moveChild(parentNode, childNode, referenceNode) {
  if (Array.isArray(childNode)) {
    moveDelimitedText(parentNode, childNode[0], childNode[1], referenceNode);
  } else {
    insertChildAt(parentNode, childNode, referenceNode);
  }
}

function removeChild(parentNode, childNode) {
  if (Array.isArray(childNode)) {
    var closingComment = childNode[1];
    childNode = childNode[0];
    removeDelimitedText(parentNode, childNode, closingComment);
    parentNode.removeChild(closingComment);
  }
  parentNode.removeChild(childNode);
}

function moveDelimitedText(parentNode, openingComment, closingComment, referenceNode) {
  var node = openingComment;
  while (true) {
    var nextNode = node.nextSibling;
    insertChildAt(parentNode, node, referenceNode);
    if (node === closingComment) {
      break;
    }
    node = nextNode;
  }
}

function removeDelimitedText(parentNode, startNode, closingComment) {
  while (true) {
    var node = startNode.nextSibling;
    if (node === closingComment) {
      // The closing comment is removed by ReactMultiChild.
      break;
    } else {
      parentNode.removeChild(node);
    }
  }
}

function replaceDelimitedText(openingComment, closingComment, stringText) {
  var parentNode = openingComment.parentNode;
  var nodeAfterComment = openingComment.nextSibling;
  if (nodeAfterComment === closingComment) {
    // There are no text nodes between the opening and closing comments; insert
    // a new one if stringText isn't empty.
    if (stringText) {
      insertChildAt(parentNode, document.createTextNode(stringText), nodeAfterComment);
    }
  } else {
    if (stringText) {
      // Set the text content of the first node after the opening comment, and
      // remove all following nodes up until the closing comment.
      setTextContent(nodeAfterComment, stringText);
      removeDelimitedText(parentNode, nodeAfterComment, closingComment);
    } else {
      removeDelimitedText(parentNode, openingComment, closingComment);
    }
  }

  if (true) {
    ReactInstrumentation.debugTool.onHostOperation({
      instanceID: ReactDOMComponentTree.getInstanceFromNode(openingComment)._debugID,
      type: 'replace text',
      payload: stringText
    });
  }
}

var dangerouslyReplaceNodeWithMarkup = Danger.dangerouslyReplaceNodeWithMarkup;
if (true) {
  dangerouslyReplaceNodeWithMarkup = function (oldChild, markup, prevInstance) {
    Danger.dangerouslyReplaceNodeWithMarkup(oldChild, markup);
    if (prevInstance._debugID !== 0) {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: prevInstance._debugID,
        type: 'replace with',
        payload: markup.toString()
      });
    } else {
      var nextInstance = ReactDOMComponentTree.getInstanceFromNode(markup.node);
      if (nextInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onHostOperation({
          instanceID: nextInstance._debugID,
          type: 'mount',
          payload: markup.toString()
        });
      }
    }
  };
}

/**
 * Operations for updating with DOM children.
 */
var DOMChildrenOperations = {
  dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup,

  replaceDelimitedText: replaceDelimitedText,

  /**
   * Updates a component's children by processing a series of updates. The
   * update configurations are each expected to have a `parentNode` property.
   *
   * @param {array<object>} updates List of update configurations.
   * @internal
   */
  processUpdates: function (parentNode, updates) {
    if (true) {
      var parentNodeDebugID = ReactDOMComponentTree.getInstanceFromNode(parentNode)._debugID;
    }

    for (var k = 0; k < updates.length; k++) {
      var update = updates[k];
      switch (update.type) {
        case 'INSERT_MARKUP':
          insertLazyTreeChildAt(parentNode, update.content, getNodeAfter(parentNode, update.afterNode));
          if (true) {
            ReactInstrumentation.debugTool.onHostOperation({
              instanceID: parentNodeDebugID,
              type: 'insert child',
              payload: {
                toIndex: update.toIndex,
                content: update.content.toString()
              }
            });
          }
          break;
        case 'MOVE_EXISTING':
          moveChild(parentNode, update.fromNode, getNodeAfter(parentNode, update.afterNode));
          if (true) {
            ReactInstrumentation.debugTool.onHostOperation({
              instanceID: parentNodeDebugID,
              type: 'move child',
              payload: { fromIndex: update.fromIndex, toIndex: update.toIndex }
            });
          }
          break;
        case 'SET_MARKUP':
          setInnerHTML(parentNode, update.content);
          if (true) {
            ReactInstrumentation.debugTool.onHostOperation({
              instanceID: parentNodeDebugID,
              type: 'replace children',
              payload: update.content.toString()
            });
          }
          break;
        case 'TEXT_CONTENT':
          setTextContent(parentNode, update.content);
          if (true) {
            ReactInstrumentation.debugTool.onHostOperation({
              instanceID: parentNodeDebugID,
              type: 'replace text',
              payload: update.content.toString()
            });
          }
          break;
        case 'REMOVE_NODE':
          removeChild(parentNode, update.fromNode);
          if (true) {
            ReactInstrumentation.debugTool.onHostOperation({
              instanceID: parentNodeDebugID,
              type: 'remove child',
              payload: { fromIndex: update.fromIndex }
            });
          }
          break;
      }
    }
  }
};

module.exports = DOMChildrenOperations;

/***/ }),
/* 42 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMNamespaces = {
  html: 'http://www.w3.org/1999/xhtml',
  mathml: 'http://www.w3.org/1998/Math/MathML',
  svg: 'http://www.w3.org/2000/svg'
};

module.exports = DOMNamespaces;

/***/ }),
/* 43 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/* globals MSApp */



/**
 * Create a function which has 'unsafe' privileges (required by windows8 apps)
 */

var createMicrosoftUnsafeLocalFunction = function (func) {
  if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
    return function (arg0, arg1, arg2, arg3) {
      MSApp.execUnsafeLocalFunction(function () {
        return func(arg0, arg1, arg2, arg3);
      });
    };
  } else {
    return func;
  }
};

module.exports = createMicrosoftUnsafeLocalFunction;

/***/ }),
/* 44 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactPropTypesSecret = __webpack_require__(72);
var propTypesFactory = __webpack_require__(57);

var React = __webpack_require__(16);
var PropTypes = propTypesFactory(React.isValidElement);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

var hasReadOnlyValue = {
  button: true,
  checkbox: true,
  image: true,
  hidden: true,
  radio: true,
  reset: true,
  submit: true
};

function _assertSingleLink(inputProps) {
  !(inputProps.checkedLink == null || inputProps.valueLink == null) ?  true ? invariant(false, 'Cannot provide a checkedLink and a valueLink. If you want to use checkedLink, you probably don\'t want to use valueLink and vice versa.') : _prodInvariant('87') : void 0;
}
function _assertValueLink(inputProps) {
  _assertSingleLink(inputProps);
  !(inputProps.value == null && inputProps.onChange == null) ?  true ? invariant(false, 'Cannot provide a valueLink and a value or onChange event. If you want to use value or onChange, you probably don\'t want to use valueLink.') : _prodInvariant('88') : void 0;
}

function _assertCheckedLink(inputProps) {
  _assertSingleLink(inputProps);
  !(inputProps.checked == null && inputProps.onChange == null) ?  true ? invariant(false, 'Cannot provide a checkedLink and a checked property or onChange event. If you want to use checked or onChange, you probably don\'t want to use checkedLink') : _prodInvariant('89') : void 0;
}

var propTypes = {
  value: function (props, propName, componentName) {
    if (!props[propName] || hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled) {
      return null;
    }
    return 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 (props, propName, componentName) {
    if (!props[propName] || props.onChange || props.readOnly || props.disabled) {
      return null;
    }
    return 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: PropTypes.func
};

var loggedTypeFailures = {};
function getDeclarationErrorAddendum(owner) {
  if (owner) {
    var name = owner.getName();
    if (name) {
      return ' Check the render method of `' + name + '`.';
    }
  }
  return '';
}

/**
 * Provide a linked `value` attribute for controlled forms. You should not use
 * this outside of the ReactDOM controlled form components.
 */
var LinkedValueUtils = {
  checkPropTypes: function (tagName, props, owner) {
    for (var propName in propTypes) {
      if (propTypes.hasOwnProperty(propName)) {
        var error = propTypes[propName](props, propName, tagName, 'prop', null, ReactPropTypesSecret);
      }
      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
        // Only monitor this failure once because there tends to be a lot of the
        // same error.
        loggedTypeFailures[error.message] = true;

        var addendum = getDeclarationErrorAddendum(owner);
         true ? warning(false, 'Failed form propType: %s%s', error.message, addendum) : void 0;
      }
    }
  },

  /**
   * @param {object} inputProps Props for form component
   * @return {*} current value of the input either from value prop or link.
   */
  getValue: function (inputProps) {
    if (inputProps.valueLink) {
      _assertValueLink(inputProps);
      return inputProps.valueLink.value;
    }
    return inputProps.value;
  },

  /**
   * @param {object} inputProps Props for form component
   * @return {*} current checked status of the input either from checked prop
   *             or link.
   */
  getChecked: function (inputProps) {
    if (inputProps.checkedLink) {
      _assertCheckedLink(inputProps);
      return inputProps.checkedLink.value;
    }
    return inputProps.checked;
  },

  /**
   * @param {object} inputProps Props for form component
   * @param {SyntheticEvent} event change event to handle
   */
  executeOnChange: function (inputProps, event) {
    if (inputProps.valueLink) {
      _assertValueLink(inputProps);
      return inputProps.valueLink.requestChange(event.target.value);
    } else if (inputProps.checkedLink) {
      _assertCheckedLink(inputProps);
      return inputProps.checkedLink.requestChange(event.target.checked);
    } else if (inputProps.onChange) {
      return inputProps.onChange.call(undefined, event);
    }
  }
};

module.exports = LinkedValueUtils;

/***/ }),
/* 45 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

var injected = false;

var ReactComponentEnvironment = {
  /**
   * Optionally injectable hook for swapping out mount images in the middle of
   * the tree.
   */
  replaceNodeWithMarkup: null,

  /**
   * Optionally injectable hook for processing a queue of child updates. Will
   * later move into MultiChildComponents.
   */
  processChildrenUpdates: null,

  injection: {
    injectEnvironment: function (environment) {
      !!injected ?  true ? invariant(false, 'ReactCompositeComponent: injectEnvironment() can only be called once.') : _prodInvariant('104') : void 0;
      ReactComponentEnvironment.replaceNodeWithMarkup = environment.replaceNodeWithMarkup;
      ReactComponentEnvironment.processChildrenUpdates = environment.processChildrenUpdates;
      injected = true;
    }
  }
};

module.exports = ReactComponentEnvironment;

/***/ }),
/* 46 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 * 
 */

/*eslint-disable no-self-compare */



var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x, y) {
  // SameValue algorithm
  if (x === y) {
    // Steps 1-5, 7-10
    // Steps 6.b-6.e: +0 != -0
    // Added the nonzero y check to make Flow happy, but it is redundant
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    // Step 6.a: NaN == NaN
    return x !== x && y !== y;
  }
}

/**
 * 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 (is(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.
  for (var i = 0; i < keysA.length; i++) {
    if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false;
    }
  }

  return true;
}

module.exports = shallowEqual;

/***/ }),
/* 47 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Given a `prevElement` and `nextElement`, determines if the existing
 * instance should be updated as opposed to being destroyed or replaced by a new
 * instance. Both arguments are elements. This ensures that this logic can
 * operate on stateless trees without any backing instance.
 *
 * @param {?object} prevElement
 * @param {?object} nextElement
 * @return {boolean} True if the existing instance should be updated.
 * @protected
 */

function shouldUpdateReactComponent(prevElement, nextElement) {
  var prevEmpty = prevElement === null || prevElement === false;
  var nextEmpty = nextElement === null || nextElement === false;
  if (prevEmpty || nextEmpty) {
    return prevEmpty === nextEmpty;
  }

  var prevType = typeof prevElement;
  var nextType = typeof nextElement;
  if (prevType === 'string' || prevType === 'number') {
    return nextType === 'string' || nextType === 'number';
  } else {
    return nextType === 'object' && prevElement.type === nextElement.type && prevElement.key === nextElement.key;
  }
}

module.exports = shouldUpdateReactComponent;

/***/ }),
/* 48 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/**
 * Escape and wrap key so it is safe to use as a reactid
 *
 * @param {string} key to be escaped.
 * @return {string} the escaped key.
 */

function escape(key) {
  var escapeRegex = /[=:]/g;
  var escaperLookup = {
    '=': '=0',
    ':': '=2'
  };
  var escapedString = ('' + key).replace(escapeRegex, function (match) {
    return escaperLookup[match];
  });

  return '$' + escapedString;
}

/**
 * Unescape and unwrap key for human-readable display
 *
 * @param {string} key to unescape.
 * @return {string} the unescaped key.
 */
function unescape(key) {
  var unescapeRegex = /(=0|=2)/g;
  var unescaperLookup = {
    '=0': '=',
    '=2': ':'
  };
  var keySubstring = key[0] === '.' && key[1] === '$' ? key.substring(2) : key.substring(1);

  return ('' + keySubstring).replace(unescapeRegex, function (match) {
    return unescaperLookup[match];
  });
}

var KeyEscapeUtils = {
  escape: escape,
  unescape: unescape
};

module.exports = KeyEscapeUtils;

/***/ }),
/* 49 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactCurrentOwner = __webpack_require__(9);
var ReactInstanceMap = __webpack_require__(23);
var ReactInstrumentation = __webpack_require__(7);
var ReactUpdates = __webpack_require__(10);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

function enqueueUpdate(internalInstance) {
  ReactUpdates.enqueueUpdate(internalInstance);
}

function formatUnexpectedArgument(arg) {
  var type = typeof arg;
  if (type !== 'object') {
    return type;
  }
  var displayName = arg.constructor && arg.constructor.name || type;
  var keys = Object.keys(arg);
  if (keys.length > 0 && keys.length < 20) {
    return displayName + ' (keys: ' + keys.join(', ') + ')';
  }
  return displayName;
}

function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
  var internalInstance = ReactInstanceMap.get(publicInstance);
  if (!internalInstance) {
    if (true) {
      var ctor = publicInstance.constructor;
      // Only warn when we have a callerName. Otherwise we should be silent.
      // We're probably calling from enqueueCallback. We don't want to warn
      // there because we already warned for the corresponding lifecycle method.
       true ? warning(!callerName, '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op. Please check the code for the %s component.', callerName, callerName, ctor && (ctor.displayName || ctor.name) || 'ReactClass') : void 0;
    }
    return null;
  }

  if (true) {
     true ? warning(ReactCurrentOwner.current == null, '%s(...): Cannot update during an existing state transition (such as ' + "within `render` or another component's constructor). Render methods " + 'should be a pure function of props and state; constructor ' + 'side-effects are an anti-pattern, but can be moved to ' + '`componentWillMount`.', callerName) : void 0;
  }

  return internalInstance;
}

/**
 * ReactUpdateQueue allows for state updates to be scheduled into a later
 * reconciliation step.
 */
var ReactUpdateQueue = {
  /**
   * Checks whether or not this composite component is mounted.
   * @param {ReactClass} publicInstance The instance we want to test.
   * @return {boolean} True if mounted, false otherwise.
   * @protected
   * @final
   */
  isMounted: function (publicInstance) {
    if (true) {
      var owner = ReactCurrentOwner.current;
      if (owner !== null) {
         true ? warning(owner._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', owner.getName() || 'A component') : void 0;
        owner._warnedAboutRefsInRender = true;
      }
    }
    var internalInstance = ReactInstanceMap.get(publicInstance);
    if (internalInstance) {
      // During componentWillMount and render this will still be null but after
      // that will always render to something. At least for now. So we can use
      // this hack.
      return !!internalInstance._renderedComponent;
    } else {
      return false;
    }
  },

  /**
   * Enqueue a callback that will be executed after all the pending updates
   * have processed.
   *
   * @param {ReactClass} publicInstance The instance to use as `this` context.
   * @param {?function} callback Called after state is updated.
   * @param {string} callerName Name of the calling function in the public API.
   * @internal
   */
  enqueueCallback: function (publicInstance, callback, callerName) {
    ReactUpdateQueue.validateCallback(callback, callerName);
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);

    // Previously we would throw an error if we didn't have an internal
    // instance. Since we want to make it a no-op instead, we mirror the same
    // behavior we have in other enqueue* methods.
    // We also need to ignore callbacks in componentWillMount. See
    // enqueueUpdates.
    if (!internalInstance) {
      return null;
    }

    if (internalInstance._pendingCallbacks) {
      internalInstance._pendingCallbacks.push(callback);
    } else {
      internalInstance._pendingCallbacks = [callback];
    }
    // TODO: The callback here is ignored when setState is called from
    // componentWillMount. Either fix it or disallow doing so completely in
    // favor of getInitialState. Alternatively, we can disallow
    // componentWillMount during server-side rendering.
    enqueueUpdate(internalInstance);
  },

  enqueueCallbackInternal: function (internalInstance, callback) {
    if (internalInstance._pendingCallbacks) {
      internalInstance._pendingCallbacks.push(callback);
    } else {
      internalInstance._pendingCallbacks = [callback];
    }
    enqueueUpdate(internalInstance);
  },

  /**
   * Forces an update. This should only be invoked when it is known with
   * certainty that we are **not** in a DOM transaction.
   *
   * You may want to call this when you know that some deeper aspect of the
   * component's state has changed but `setState` was not called.
   *
   * This will not invoke `shouldComponentUpdate`, but it will invoke
   * `componentWillUpdate` and `componentDidUpdate`.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @internal
   */
  enqueueForceUpdate: function (publicInstance) {
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'forceUpdate');

    if (!internalInstance) {
      return;
    }

    internalInstance._pendingForceUpdate = true;

    enqueueUpdate(internalInstance);
  },

  /**
   * Replaces all of the state. Always use this or `setState` to mutate state.
   * You should treat `this.state` as immutable.
   *
   * There is no guarantee that `this.state` will be immediately updated, so
   * accessing `this.state` after calling this method may return the old value.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object} completeState Next state.
   * @internal
   */
  enqueueReplaceState: function (publicInstance, completeState, callback) {
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'replaceState');

    if (!internalInstance) {
      return;
    }

    internalInstance._pendingStateQueue = [completeState];
    internalInstance._pendingReplaceState = true;

    // Future-proof 15.5
    if (callback !== undefined && callback !== null) {
      ReactUpdateQueue.validateCallback(callback, 'replaceState');
      if (internalInstance._pendingCallbacks) {
        internalInstance._pendingCallbacks.push(callback);
      } else {
        internalInstance._pendingCallbacks = [callback];
      }
    }

    enqueueUpdate(internalInstance);
  },

  /**
   * Sets a subset of the state. This only exists because _pendingState is
   * internal. This provides a merging strategy that is not available to deep
   * properties which is confusing. TODO: Expose pendingState or don't use it
   * during the merge.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object} partialState Next partial state to be merged with state.
   * @internal
   */
  enqueueSetState: function (publicInstance, partialState) {
    if (true) {
      ReactInstrumentation.debugTool.onSetState();
       true ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : void 0;
    }

    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');

    if (!internalInstance) {
      return;
    }

    var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
    queue.push(partialState);

    enqueueUpdate(internalInstance);
  },

  enqueueElementInternal: function (internalInstance, nextElement, nextContext) {
    internalInstance._pendingElement = nextElement;
    // TODO: introduce _pendingContext instead of setting it directly.
    internalInstance._context = nextContext;
    enqueueUpdate(internalInstance);
  },

  validateCallback: function (callback, callerName) {
    !(!callback || typeof callback === 'function') ?  true ? invariant(false, '%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.', callerName, formatUnexpectedArgument(callback)) : _prodInvariant('122', callerName, formatUnexpectedArgument(callback)) : void 0;
  }
};

module.exports = ReactUpdateQueue;

/***/ }),
/* 50 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var emptyFunction = __webpack_require__(8);
var warning = __webpack_require__(1);

var validateDOMNesting = emptyFunction;

if (true) {
  // This validation code was written based on the HTML5 parsing spec:
  // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
  //
  // Note: this does not catch all invalid nesting, nor does it try to (as it's
  // not clear what practical benefit doing so provides); instead, we warn only
  // for cases where the parser will give a parse tree differing from what React
  // intended. For example, <b><div></div></b> is invalid but we don't warn
  // because it still parses correctly; we do warn for other cases like nested
  // <p> tags where the beginning of the second element implicitly closes the
  // first, causing a confusing mess.

  // https://html.spec.whatwg.org/multipage/syntax.html#special
  var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp'];

  // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
  var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template',

  // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point
  // TODO: Distinguish by namespace here -- for <title>, including it here
  // errs on the side of fewer warnings
  'foreignObject', 'desc', 'title'];

  // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope
  var buttonScopeTags = inScopeTags.concat(['button']);

  // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags
  var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt'];

  var emptyAncestorInfo = {
    current: null,

    formTag: null,
    aTagInScope: null,
    buttonTagInScope: null,
    nobrTagInScope: null,
    pTagInButtonScope: null,

    listItemTagAutoclosing: null,
    dlItemTagAutoclosing: null
  };

  var updatedAncestorInfo = function (oldInfo, tag, instance) {
    var ancestorInfo = _assign({}, oldInfo || emptyAncestorInfo);
    var info = { tag: tag, instance: instance };

    if (inScopeTags.indexOf(tag) !== -1) {
      ancestorInfo.aTagInScope = null;
      ancestorInfo.buttonTagInScope = null;
      ancestorInfo.nobrTagInScope = null;
    }
    if (buttonScopeTags.indexOf(tag) !== -1) {
      ancestorInfo.pTagInButtonScope = null;
    }

    // See rules for 'li', 'dd', 'dt' start tags in
    // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
    if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') {
      ancestorInfo.listItemTagAutoclosing = null;
      ancestorInfo.dlItemTagAutoclosing = null;
    }

    ancestorInfo.current = info;

    if (tag === 'form') {
      ancestorInfo.formTag = info;
    }
    if (tag === 'a') {
      ancestorInfo.aTagInScope = info;
    }
    if (tag === 'button') {
      ancestorInfo.buttonTagInScope = info;
    }
    if (tag === 'nobr') {
      ancestorInfo.nobrTagInScope = info;
    }
    if (tag === 'p') {
      ancestorInfo.pTagInButtonScope = info;
    }
    if (tag === 'li') {
      ancestorInfo.listItemTagAutoclosing = info;
    }
    if (tag === 'dd' || tag === 'dt') {
      ancestorInfo.dlItemTagAutoclosing = info;
    }

    return ancestorInfo;
  };

  /**
   * Returns whether
   */
  var isTagValidWithParent = function (tag, parentTag) {
    // First, let's check if we're in an unusual parsing mode...
    switch (parentTag) {
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect
      case 'select':
        return tag === 'option' || tag === 'optgroup' || tag === '#text';
      case 'optgroup':
        return tag === 'option' || tag === '#text';
      // Strictly speaking, seeing an <option> doesn't mean we're in a <select>
      // but
      case 'option':
        return tag === '#text';
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption
      // No special behavior since these rules fall back to "in body" mode for
      // all except special table nodes which cause bad parsing behavior anyway.

      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr
      case 'tr':
        return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template';
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody
      case 'tbody':
      case 'thead':
      case 'tfoot':
        return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template';
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup
      case 'colgroup':
        return tag === 'col' || tag === 'template';
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable
      case 'table':
        return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template';
      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead
      case 'head':
        return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template';
      // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element
      case 'html':
        return tag === 'head' || tag === 'body';
      case '#document':
        return tag === 'html';
    }

    // Probably in the "in body" parsing mode, so we outlaw only tag combos
    // where the parsing rules cause implicit opens or closes to be added.
    // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
    switch (tag) {
      case 'h1':
      case 'h2':
      case 'h3':
      case 'h4':
      case 'h5':
      case 'h6':
        return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6';

      case 'rp':
      case 'rt':
        return impliedEndTags.indexOf(parentTag) === -1;

      case 'body':
      case 'caption':
      case 'col':
      case 'colgroup':
      case 'frame':
      case 'head':
      case 'html':
      case 'tbody':
      case 'td':
      case 'tfoot':
      case 'th':
      case 'thead':
      case 'tr':
        // These tags are only valid with a few parents that have special child
        // parsing rules -- if we're down here, then none of those matched and
        // so we allow it only if we don't know what the parent is, as all other
        // cases are invalid.
        return parentTag == null;
    }

    return true;
  };

  /**
   * Returns whether
   */
  var findInvalidAncestorForTag = function (tag, ancestorInfo) {
    switch (tag) {
      case 'address':
      case 'article':
      case 'aside':
      case 'blockquote':
      case 'center':
      case 'details':
      case 'dialog':
      case 'dir':
      case 'div':
      case 'dl':
      case 'fieldset':
      case 'figcaption':
      case 'figure':
      case 'footer':
      case 'header':
      case 'hgroup':
      case 'main':
      case 'menu':
      case 'nav':
      case 'ol':
      case 'p':
      case 'section':
      case 'summary':
      case 'ul':
      case 'pre':
      case 'listing':
      case 'table':
      case 'hr':
      case 'xmp':
      case 'h1':
      case 'h2':
      case 'h3':
      case 'h4':
      case 'h5':
      case 'h6':
        return ancestorInfo.pTagInButtonScope;

      case 'form':
        return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope;

      case 'li':
        return ancestorInfo.listItemTagAutoclosing;

      case 'dd':
      case 'dt':
        return ancestorInfo.dlItemTagAutoclosing;

      case 'button':
        return ancestorInfo.buttonTagInScope;

      case 'a':
        // Spec says something about storing a list of markers, but it sounds
        // equivalent to this check.
        return ancestorInfo.aTagInScope;

      case 'nobr':
        return ancestorInfo.nobrTagInScope;
    }

    return null;
  };

  /**
   * Given a ReactCompositeComponent instance, return a list of its recursive
   * owners, starting at the root and ending with the instance itself.
   */
  var findOwnerStack = function (instance) {
    if (!instance) {
      return [];
    }

    var stack = [];
    do {
      stack.push(instance);
    } while (instance = instance._currentElement._owner);
    stack.reverse();
    return stack;
  };

  var didWarn = {};

  validateDOMNesting = function (childTag, childText, childInstance, ancestorInfo) {
    ancestorInfo = ancestorInfo || emptyAncestorInfo;
    var parentInfo = ancestorInfo.current;
    var parentTag = parentInfo && parentInfo.tag;

    if (childText != null) {
       true ? warning(childTag == null, 'validateDOMNesting: when childText is passed, childTag should be null') : void 0;
      childTag = '#text';
    }

    var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo;
    var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo);
    var problematic = invalidParent || invalidAncestor;

    if (problematic) {
      var ancestorTag = problematic.tag;
      var ancestorInstance = problematic.instance;

      var childOwner = childInstance && childInstance._currentElement._owner;
      var ancestorOwner = ancestorInstance && ancestorInstance._currentElement._owner;

      var childOwners = findOwnerStack(childOwner);
      var ancestorOwners = findOwnerStack(ancestorOwner);

      var minStackLen = Math.min(childOwners.length, ancestorOwners.length);
      var i;

      var deepestCommon = -1;
      for (i = 0; i < minStackLen; i++) {
        if (childOwners[i] === ancestorOwners[i]) {
          deepestCommon = i;
        } else {
          break;
        }
      }

      var UNKNOWN = '(unknown)';
      var childOwnerNames = childOwners.slice(deepestCommon + 1).map(function (inst) {
        return inst.getName() || UNKNOWN;
      });
      var ancestorOwnerNames = ancestorOwners.slice(deepestCommon + 1).map(function (inst) {
        return inst.getName() || UNKNOWN;
      });
      var ownerInfo = [].concat(
      // If the parent and child instances have a common owner ancestor, start
      // with that -- otherwise we just start with the parent's owners.
      deepestCommon !== -1 ? childOwners[deepestCommon].getName() || UNKNOWN : [], ancestorOwnerNames, ancestorTag,
      // If we're warning about an invalid (non-parent) ancestry, add '...'
      invalidAncestor ? ['...'] : [], childOwnerNames, childTag).join(' > ');

      var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + ownerInfo;
      if (didWarn[warnKey]) {
        return;
      }
      didWarn[warnKey] = true;

      var tagDisplayName = childTag;
      var whitespaceInfo = '';
      if (childTag === '#text') {
        if (/\S/.test(childText)) {
          tagDisplayName = 'Text nodes';
        } else {
          tagDisplayName = 'Whitespace text nodes';
          whitespaceInfo = " Make sure you don't have any extra whitespace between tags on " + 'each line of your source code.';
        }
      } else {
        tagDisplayName = '<' + childTag + '>';
      }

      if (invalidParent) {
        var info = '';
        if (ancestorTag === 'table' && childTag === 'tr') {
          info += ' Add a <tbody> to your code to match the DOM tree generated by ' + 'the browser.';
        }
         true ? warning(false, 'validateDOMNesting(...): %s cannot appear as a child of <%s>.%s ' + 'See %s.%s', tagDisplayName, ancestorTag, whitespaceInfo, ownerInfo, info) : void 0;
      } else {
         true ? warning(false, 'validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>. See %s.', tagDisplayName, ancestorTag, ownerInfo) : void 0;
      }
    }
  };

  validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;

  // For testing
  validateDOMNesting.isTagValidInContext = function (tag, ancestorInfo) {
    ancestorInfo = ancestorInfo || emptyAncestorInfo;
    var parentInfo = ancestorInfo.current;
    var parentTag = parentInfo && parentInfo.tag;
    return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo);
  };
}

module.exports = validateDOMNesting;

/***/ }),
/* 51 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * `charCode` represents the actual "character code" and is safe to use with
 * `String.fromCharCode`. As such, only keys that correspond to printable
 * characters produce a valid `charCode`, the only exception to this is Enter.
 * The Tab-key is considered non-printable and does not have a `charCode`,
 * presumably because it does not produce a tab-character in browsers.
 *
 * @param {object} nativeEvent Native browser event.
 * @return {number} Normalized `charCode` property.
 */

function getEventCharCode(nativeEvent) {
  var charCode;
  var keyCode = nativeEvent.keyCode;

  if ('charCode' in nativeEvent) {
    charCode = nativeEvent.charCode;

    // FF does not set `charCode` for the Enter-key, check against `keyCode`.
    if (charCode === 0 && keyCode === 13) {
      charCode = 13;
    }
  } else {
    // IE8 does not implement `charCode`, but `keyCode` has the correct value.
    charCode = keyCode;
  }

  // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
  // Must not discard the (non-)printable Enter-key.
  if (charCode >= 32 || charCode === 13) {
    return charCode;
  }

  return 0;
}

module.exports = getEventCharCode;

/***/ }),
/* 52 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(17),
    _assign = __webpack_require__(3);

var ReactNoopUpdateQueue = __webpack_require__(53);

var canDefineProperty = __webpack_require__(26);
var emptyObject = __webpack_require__(27);
var invariant = __webpack_require__(0);
var lowPriorityWarning = __webpack_require__(35);

/**
 * Base class helpers for the updating state of a component.
 */
function ReactComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

ReactComponent.prototype.isReactComponent = {};

/**
 * Sets a subset of the state. Always use this to mutate
 * state. You should treat `this.state` as immutable.
 *
 * There is no guarantee that `this.state` will be immediately updated, so
 * accessing `this.state` after calling this method may return the old value.
 *
 * There is no guarantee that calls to `setState` will run synchronously,
 * as they may eventually be batched together.  You can provide an optional
 * callback that will be executed when the call to setState is actually
 * completed.
 *
 * When a function is provided to setState, it will be called at some point in
 * the future (not synchronously). It will be called with the up to date
 * component arguments (state, props, context). These values can be different
 * from this.* because your function may be called after receiveProps but before
 * shouldComponentUpdate, and this new state, props, and context will not yet be
 * assigned to this.
 *
 * @param {object|function} partialState Next partial state or function to
 *        produce next partial state to be merged with current state.
 * @param {?function} callback Called after state is updated.
 * @final
 * @protected
 */
ReactComponent.prototype.setState = function (partialState, callback) {
  !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ?  true ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : _prodInvariant('85') : void 0;
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState');
  }
};

/**
 * Forces an update. This should only be invoked when it is known with
 * certainty that we are **not** in a DOM transaction.
 *
 * You may want to call this when you know that some deeper aspect of the
 * component's state has changed but `setState` was not called.
 *
 * This will not invoke `shouldComponentUpdate`, but it will invoke
 * `componentWillUpdate` and `componentDidUpdate`.
 *
 * @param {?function} callback Called after update is complete.
 * @final
 * @protected
 */
ReactComponent.prototype.forceUpdate = function (callback) {
  this.updater.enqueueForceUpdate(this);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'forceUpdate');
  }
};

/**
 * Deprecated APIs. These APIs used to exist on classic React classes but since
 * we would like to deprecate them, we're not going to move them over to this
 * modern base class. Instead, we define a getter that warns if it's accessed.
 */
if (true) {
  var deprecatedAPIs = {
    isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'],
    replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).']
  };
  var defineDeprecationWarning = function (methodName, info) {
    if (canDefineProperty) {
      Object.defineProperty(ReactComponent.prototype, methodName, {
        get: function () {
          lowPriorityWarning(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]);
          return undefined;
        }
      });
    }
  };
  for (var fnName in deprecatedAPIs) {
    if (deprecatedAPIs.hasOwnProperty(fnName)) {
      defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
    }
  }
}

/**
 * Base class helpers for the updating state of a component.
 */
function ReactPureComponent(props, context, updater) {
  // Duplicated from ReactComponent.
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

function ComponentDummy() {}
ComponentDummy.prototype = ReactComponent.prototype;
ReactPureComponent.prototype = new ComponentDummy();
ReactPureComponent.prototype.constructor = ReactPureComponent;
// Avoid an extra prototype jump for these methods.
_assign(ReactPureComponent.prototype, ReactComponent.prototype);
ReactPureComponent.prototype.isPureReactComponent = true;

module.exports = {
  Component: ReactComponent,
  PureComponent: ReactPureComponent
};

/***/ }),
/* 53 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var warning = __webpack_require__(1);

function warnNoop(publicInstance, callerName) {
  if (true) {
    var constructor = publicInstance.constructor;
     true ? warning(false, '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op. Please check the code for the %s component.', callerName, callerName, constructor && (constructor.displayName || constructor.name) || 'ReactClass') : void 0;
  }
}

/**
 * This is the abstract API for an update queue.
 */
var ReactNoopUpdateQueue = {
  /**
   * Checks whether or not this composite component is mounted.
   * @param {ReactClass} publicInstance The instance we want to test.
   * @return {boolean} True if mounted, false otherwise.
   * @protected
   * @final
   */
  isMounted: function (publicInstance) {
    return false;
  },

  /**
   * Enqueue a callback that will be executed after all the pending updates
   * have processed.
   *
   * @param {ReactClass} publicInstance The instance to use as `this` context.
   * @param {?function} callback Called after state is updated.
   * @internal
   */
  enqueueCallback: function (publicInstance, callback) {},

  /**
   * Forces an update. This should only be invoked when it is known with
   * certainty that we are **not** in a DOM transaction.
   *
   * You may want to call this when you know that some deeper aspect of the
   * component's state has changed but `setState` was not called.
   *
   * This will not invoke `shouldComponentUpdate`, but it will invoke
   * `componentWillUpdate` and `componentDidUpdate`.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @internal
   */
  enqueueForceUpdate: function (publicInstance) {
    warnNoop(publicInstance, 'forceUpdate');
  },

  /**
   * Replaces all of the state. Always use this or `setState` to mutate state.
   * You should treat `this.state` as immutable.
   *
   * There is no guarantee that `this.state` will be immediately updated, so
   * accessing `this.state` after calling this method may return the old value.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object} completeState Next state.
   * @internal
   */
  enqueueReplaceState: function (publicInstance, completeState) {
    warnNoop(publicInstance, 'replaceState');
  },

  /**
   * Sets a subset of the state. This only exists because _pendingState is
   * internal. This provides a merging strategy that is not available to deep
   * properties which is confusing. TODO: Expose pendingState or don't use it
   * during the merge.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object} partialState Next partial state to be merged with state.
   * @internal
   */
  enqueueSetState: function (publicInstance, partialState) {
    warnNoop(publicInstance, 'setState');
  }
};

module.exports = ReactNoopUpdateQueue;

/***/ }),
/* 54 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



// The Symbol used to tag the ReactElement type. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.

var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7;

module.exports = REACT_ELEMENT_TYPE;

/***/ }),
/* 55 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/* global Symbol */

var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.

/**
 * Returns the iterator method function contained on the iterable object.
 *
 * Be sure to invoke the function with the iterable as context:
 *
 *     var iteratorFn = getIteratorFn(myIterable);
 *     if (iteratorFn) {
 *       var iterator = iteratorFn.call(myIterable);
 *       ...
 *     }
 *
 * @param {?object} maybeIterable
 * @return {?function}
 */
function getIteratorFn(maybeIterable) {
  var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
  if (typeof iteratorFn === 'function') {
    return iteratorFn;
  }
}

module.exports = getIteratorFn;

/***/ }),
/* 56 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/**
 * ReactElementValidator provides a wrapper around a element factory
 * which validates the props passed to the element. This is intended to be
 * used only in DEV and could be replaced by a static type checker for languages
 * that support it.
 */



var ReactCurrentOwner = __webpack_require__(9);
var ReactComponentTreeHook = __webpack_require__(6);
var ReactElement = __webpack_require__(14);

var checkReactTypeSpec = __webpack_require__(95);

var canDefineProperty = __webpack_require__(26);
var getIteratorFn = __webpack_require__(55);
var warning = __webpack_require__(1);
var lowPriorityWarning = __webpack_require__(35);

function getDeclarationErrorAddendum() {
  if (ReactCurrentOwner.current) {
    var name = ReactCurrentOwner.current.getName();
    if (name) {
      return ' Check the render method of `' + name + '`.';
    }
  }
  return '';
}

function getSourceInfoErrorAddendum(elementProps) {
  if (elementProps !== null && elementProps !== undefined && elementProps.__source !== undefined) {
    var source = elementProps.__source;
    var fileName = source.fileName.replace(/^.*[\\\/]/, '');
    var lineNumber = source.lineNumber;
    return ' Check your code at ' + fileName + ':' + lineNumber + '.';
  }
  return '';
}

/**
 * Warn if there's no key explicitly set on dynamic arrays of children or
 * object keys are not valid. This allows us to keep track of children between
 * updates.
 */
var ownerHasKeyUseWarning = {};

function getCurrentComponentErrorInfo(parentType) {
  var info = getDeclarationErrorAddendum();

  if (!info) {
    var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name;
    if (parentName) {
      info = ' Check the top-level render call using <' + parentName + '>.';
    }
  }
  return info;
}

/**
 * Warn if the element doesn't have an explicit key assigned to it.
 * This element is in an array. The array could grow and shrink or be
 * reordered. All children that haven't already been validated are required to
 * have a "key" property assigned to it. Error statuses are cached so a warning
 * will only be shown once.
 *
 * @internal
 * @param {ReactElement} element Element that requires a key.
 * @param {*} parentType element's parent's type.
 */
function validateExplicitKey(element, parentType) {
  if (!element._store || element._store.validated || element.key != null) {
    return;
  }
  element._store.validated = true;

  var memoizer = ownerHasKeyUseWarning.uniqueKey || (ownerHasKeyUseWarning.uniqueKey = {});

  var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
  if (memoizer[currentComponentErrorInfo]) {
    return;
  }
  memoizer[currentComponentErrorInfo] = true;

  // Usually the current owner is the offender, but if it accepts children as a
  // property, it may be the creator of the child that's responsible for
  // assigning it a key.
  var childOwner = '';
  if (element && element._owner && element._owner !== ReactCurrentOwner.current) {
    // Give the component that originally created this child.
    childOwner = ' It was passed a child from ' + element._owner.getName() + '.';
  }

   true ? warning(false, 'Each child in an array or iterator should have a unique "key" prop.' + '%s%s See https://fb.me/react-warning-keys for more information.%s', currentComponentErrorInfo, childOwner, ReactComponentTreeHook.getCurrentStackAddendum(element)) : void 0;
}

/**
 * Ensure that every element either is passed in a static location, in an
 * array with an explicit keys property defined, or in an object literal
 * with valid key property.
 *
 * @internal
 * @param {ReactNode} node Statically passed child of any type.
 * @param {*} parentType node's parent's type.
 */
function validateChildKeys(node, parentType) {
  if (typeof node !== 'object') {
    return;
  }
  if (Array.isArray(node)) {
    for (var i = 0; i < node.length; i++) {
      var child = node[i];
      if (ReactElement.isValidElement(child)) {
        validateExplicitKey(child, parentType);
      }
    }
  } else if (ReactElement.isValidElement(node)) {
    // This element was passed in a valid location.
    if (node._store) {
      node._store.validated = true;
    }
  } else if (node) {
    var iteratorFn = getIteratorFn(node);
    // Entry iterators provide implicit keys.
    if (iteratorFn) {
      if (iteratorFn !== node.entries) {
        var iterator = iteratorFn.call(node);
        var step;
        while (!(step = iterator.next()).done) {
          if (ReactElement.isValidElement(step.value)) {
            validateExplicitKey(step.value, parentType);
          }
        }
      }
    }
  }
}

/**
 * Given an element, validate that its props follow the propTypes definition,
 * provided by the type.
 *
 * @param {ReactElement} element
 */
function validatePropTypes(element) {
  var componentClass = element.type;
  if (typeof componentClass !== 'function') {
    return;
  }
  var name = componentClass.displayName || componentClass.name;
  if (componentClass.propTypes) {
    checkReactTypeSpec(componentClass.propTypes, element.props, 'prop', name, element, null);
  }
  if (typeof componentClass.getDefaultProps === 'function') {
     true ? warning(componentClass.getDefaultProps.isReactClassApproved, 'getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.') : void 0;
  }
}

var ReactElementValidator = {
  createElement: function (type, props, children) {
    var validType = typeof type === 'string' || typeof type === 'function';
    // We warn in this case but don't throw. We expect the element creation to
    // succeed and there will likely be errors in render.
    if (!validType) {
      if (typeof type !== 'function' && typeof type !== 'string') {
        var info = '';
        if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
          info += ' You likely forgot to export your component from the file ' + "it's defined in.";
        }

        var sourceInfo = getSourceInfoErrorAddendum(props);
        if (sourceInfo) {
          info += sourceInfo;
        } else {
          info += getDeclarationErrorAddendum();
        }

        info += ReactComponentTreeHook.getCurrentStackAddendum();

        var currentSource = props !== null && props !== undefined && props.__source !== undefined ? props.__source : null;
        ReactComponentTreeHook.pushNonStandardWarningStack(true, currentSource);
         true ? warning(false, 'React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', type == null ? type : typeof type, info) : void 0;
        ReactComponentTreeHook.popNonStandardWarningStack();
      }
    }

    var element = ReactElement.createElement.apply(this, arguments);

    // The result can be nullish if a mock or a custom function is used.
    // TODO: Drop this when these are no longer allowed as the type argument.
    if (element == null) {
      return element;
    }

    // Skip key warning if the type isn't valid since our key validation logic
    // doesn't expect a non-string/function type and can throw confusing errors.
    // We don't want exception behavior to differ between dev and prod.
    // (Rendering will throw with a helpful message and as soon as the type is
    // fixed, the key warnings will appear.)
    if (validType) {
      for (var i = 2; i < arguments.length; i++) {
        validateChildKeys(arguments[i], type);
      }
    }

    validatePropTypes(element);

    return element;
  },

  createFactory: function (type) {
    var validatedFactory = ReactElementValidator.createElement.bind(null, type);
    // Legacy hook TODO: Warn if this is accessed
    validatedFactory.type = type;

    if (true) {
      if (canDefineProperty) {
        Object.defineProperty(validatedFactory, 'type', {
          enumerable: false,
          get: function () {
            lowPriorityWarning(false, 'Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.');
            Object.defineProperty(this, 'type', {
              value: type
            });
            return type;
          }
        });
      }
    }

    return validatedFactory;
  },

  cloneElement: function (element, props, children) {
    var newElement = ReactElement.cloneElement.apply(this, arguments);
    for (var i = 2; i < arguments.length; i++) {
      validateChildKeys(arguments[i], newElement.type);
    }
    validatePropTypes(newElement);
    return newElement;
  }
};

module.exports = ReactElementValidator;

/***/ }),
/* 57 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */



// React 15.5 references this module, and assumes PropTypes are still callable in production.
// Therefore we re-export development-only version with all the PropTypes checks here.
// However if one is migrating to the `prop-types` npm library, they will go through the
// `index.js` entry point, and it will branch depending on the environment.
var factory = __webpack_require__(85);
module.exports = function(isValidElement) {
  // It is still allowed in 15.5.
  var throwOnDirectAccess = false;
  return factory(isValidElement, throwOnDirectAccess);
};


/***/ }),
/* 58 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */



var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';

module.exports = ReactPropTypesSecret;


/***/ }),
/* 59 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactDOMComponentFlags = {
  hasCachedChildNodes: 1 << 0
};

module.exports = ReactDOMComponentFlags;

/***/ }),
/* 60 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

/**
 * Accumulates items that must not be null or undefined into the first one. This
 * is used to conserve memory by avoiding array allocations, and thus sacrifices
 * API cleanness. Since `current` can be null before being passed in and not
 * null after this function, make sure to assign it back to `current`:
 *
 * `a = accumulateInto(a, b);`
 *
 * This API should be sparingly used. Try `accumulate` for something cleaner.
 *
 * @return {*|array<*>} An accumulation of items.
 */

function accumulateInto(current, next) {
  !(next != null) ?  true ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : _prodInvariant('30') : void 0;

  if (current == null) {
    return next;
  }

  // Both are not empty. Warning: Never call x.concat(y) when you are not
  // certain that x is an Array (x could be a string with concat method).
  if (Array.isArray(current)) {
    if (Array.isArray(next)) {
      current.push.apply(current, next);
      return current;
    }
    current.push(next);
    return current;
  }

  if (Array.isArray(next)) {
    // A bit too dangerous to mutate `next`.
    return [current].concat(next);
  }

  return [current, next];
}

module.exports = accumulateInto;

/***/ }),
/* 61 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/**
 * @param {array} arr an "accumulation" of items which is either an Array or
 * a single item. Useful when paired with the `accumulate` module. This is a
 * simple utility that allows us to reason about a collection of items, but
 * handling the case when there is exactly one item (and we do not need to
 * allocate an array).
 */

function forEachAccumulated(arr, cb, scope) {
  if (Array.isArray(arr)) {
    arr.forEach(cb, scope);
  } else if (arr) {
    cb.call(scope, arr);
  }
}

module.exports = forEachAccumulated;

/***/ }),
/* 62 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);

var contentKey = null;

/**
 * Gets the key used to access text content on a DOM node.
 *
 * @return {?string} Key used to access text content.
 * @internal
 */
function getTextContentAccessor() {
  if (!contentKey && ExecutionEnvironment.canUseDOM) {
    // Prefer textContent to innerText because many browsers support both but
    // SVG <text> elements don't support innerText even when <div> does.
    contentKey = 'textContent' in document.documentElement ? 'textContent' : 'innerText';
  }
  return contentKey;
}

module.exports = getTextContentAccessor;

/***/ }),
/* 63 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var PooledClass = __webpack_require__(15);

var invariant = __webpack_require__(0);

/**
 * A specialized pseudo-event module to help keep track of components waiting to
 * be notified when their DOM representations are available for use.
 *
 * This implements `PooledClass`, so you should never need to instantiate this.
 * Instead, use `CallbackQueue.getPooled()`.
 *
 * @class ReactMountReady
 * @implements PooledClass
 * @internal
 */

var CallbackQueue = function () {
  function CallbackQueue(arg) {
    _classCallCheck(this, CallbackQueue);

    this._callbacks = null;
    this._contexts = null;
    this._arg = arg;
  }

  /**
   * Enqueues a callback to be invoked when `notifyAll` is invoked.
   *
   * @param {function} callback Invoked when `notifyAll` is invoked.
   * @param {?object} context Context to call `callback` with.
   * @internal
   */


  CallbackQueue.prototype.enqueue = function enqueue(callback, context) {
    this._callbacks = this._callbacks || [];
    this._callbacks.push(callback);
    this._contexts = this._contexts || [];
    this._contexts.push(context);
  };

  /**
   * Invokes all enqueued callbacks and clears the queue. This is invoked after
   * the DOM representation of a component has been created or updated.
   *
   * @internal
   */


  CallbackQueue.prototype.notifyAll = function notifyAll() {
    var callbacks = this._callbacks;
    var contexts = this._contexts;
    var arg = this._arg;
    if (callbacks && contexts) {
      !(callbacks.length === contexts.length) ?  true ? invariant(false, 'Mismatched list of contexts in callback queue') : _prodInvariant('24') : void 0;
      this._callbacks = null;
      this._contexts = null;
      for (var i = 0; i < callbacks.length; i++) {
        callbacks[i].call(contexts[i], arg);
      }
      callbacks.length = 0;
      contexts.length = 0;
    }
  };

  CallbackQueue.prototype.checkpoint = function checkpoint() {
    return this._callbacks ? this._callbacks.length : 0;
  };

  CallbackQueue.prototype.rollback = function rollback(len) {
    if (this._callbacks && this._contexts) {
      this._callbacks.length = len;
      this._contexts.length = len;
    }
  };

  /**
   * Resets the internal queue.
   *
   * @internal
   */


  CallbackQueue.prototype.reset = function reset() {
    this._callbacks = null;
    this._contexts = null;
  };

  /**
   * `PooledClass` looks for this.
   */


  CallbackQueue.prototype.destructor = function destructor() {
    this.reset();
  };

  return CallbackQueue;
}();

module.exports = PooledClass.addPoolingTo(CallbackQueue);

/***/ }),
/* 64 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactFeatureFlags = {
  // When true, call console.time() before and .timeEnd() after each top-level
  // render (both initial renders and updates). Useful when looking at prod-mode
  // timeline profiles in Chrome, for example.
  logTopLevelRenders: false
};

module.exports = ReactFeatureFlags;

/***/ }),
/* 65 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactDOMComponentTree = __webpack_require__(4);

function isCheckable(elem) {
  var type = elem.type;
  var nodeName = elem.nodeName;
  return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio');
}

function getTracker(inst) {
  return inst._wrapperState.valueTracker;
}

function attachTracker(inst, tracker) {
  inst._wrapperState.valueTracker = tracker;
}

function detachTracker(inst) {
  inst._wrapperState.valueTracker = null;
}

function getValueFromNode(node) {
  var value;
  if (node) {
    value = isCheckable(node) ? '' + node.checked : node.value;
  }
  return value;
}

var inputValueTracking = {
  // exposed for testing
  _getTrackerFromNode: function (node) {
    return getTracker(ReactDOMComponentTree.getInstanceFromNode(node));
  },


  track: function (inst) {
    if (getTracker(inst)) {
      return;
    }

    var node = ReactDOMComponentTree.getNodeFromInstance(inst);
    var valueField = isCheckable(node) ? 'checked' : 'value';
    var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField);

    var currentValue = '' + node[valueField];

    // if someone has already defined a value or Safari, then bail
    // and don't track value will cause over reporting of changes,
    // but it's better then a hard failure
    // (needed for certain tests that spyOn input values and Safari)
    if (node.hasOwnProperty(valueField) || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') {
      return;
    }

    Object.defineProperty(node, valueField, {
      enumerable: descriptor.enumerable,
      configurable: true,
      get: function () {
        return descriptor.get.call(this);
      },
      set: function (value) {
        currentValue = '' + value;
        descriptor.set.call(this, value);
      }
    });

    attachTracker(inst, {
      getValue: function () {
        return currentValue;
      },
      setValue: function (value) {
        currentValue = '' + value;
      },
      stopTracking: function () {
        detachTracker(inst);
        delete node[valueField];
      }
    });
  },

  updateValueIfChanged: function (inst) {
    if (!inst) {
      return false;
    }
    var tracker = getTracker(inst);

    if (!tracker) {
      inputValueTracking.track(inst);
      return true;
    }

    var lastValue = tracker.getValue();
    var nextValue = getValueFromNode(ReactDOMComponentTree.getNodeFromInstance(inst));

    if (nextValue !== lastValue) {
      tracker.setValue(nextValue);
      return true;
    }

    return false;
  },
  stopTracking: function (inst) {
    var tracker = getTracker(inst);
    if (tracker) {
      tracker.stopTracking();
    }
  }
};

module.exports = inputValueTracking;

/***/ }),
/* 66 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/**
 * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
 */

var supportedInputTypes = {
  color: true,
  date: true,
  datetime: true,
  'datetime-local': true,
  email: true,
  month: true,
  number: true,
  password: true,
  range: true,
  search: true,
  tel: true,
  text: true,
  time: true,
  url: true,
  week: true
};

function isTextInputElement(elem) {
  var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();

  if (nodeName === 'input') {
    return !!supportedInputTypes[elem.type];
  }

  if (nodeName === 'textarea') {
    return true;
  }

  return false;
}

module.exports = isTextInputElement;

/***/ }),
/* 67 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ViewportMetrics = {
  currentScrollLeft: 0,

  currentScrollTop: 0,

  refreshScrollValues: function (scrollPosition) {
    ViewportMetrics.currentScrollLeft = scrollPosition.x;
    ViewportMetrics.currentScrollTop = scrollPosition.y;
  }
};

module.exports = ViewportMetrics;

/***/ }),
/* 68 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);
var escapeTextContentForBrowser = __webpack_require__(32);
var setInnerHTML = __webpack_require__(31);

/**
 * Set the textContent property of a node, ensuring that whitespace is preserved
 * even in IE8. innerText is a poor substitute for textContent and, among many
 * issues, inserts <br> instead of the literal newline chars. innerHTML behaves
 * as it should.
 *
 * @param {DOMElement} node
 * @param {string} text
 * @internal
 */
var setTextContent = function (node, text) {
  if (text) {
    var firstChild = node.firstChild;

    if (firstChild && firstChild === node.lastChild && firstChild.nodeType === 3) {
      firstChild.nodeValue = text;
      return;
    }
  }
  node.textContent = text;
};

if (ExecutionEnvironment.canUseDOM) {
  if (!('textContent' in document.documentElement)) {
    setTextContent = function (node, text) {
      if (node.nodeType === 3) {
        node.nodeValue = text;
        return;
      }
      setInnerHTML(node, escapeTextContentForBrowser(text));
    };
  }
}

module.exports = setTextContent;

/***/ }),
/* 69 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * @param {DOMElement} node input/textarea to focus
 */

function focusNode(node) {
  // IE8 can throw "Can't move focus to the control because it is invisible,
  // not enabled, or of a type that does not accept the focus." for all kinds of
  // reasons that are too expensive and fragile to test.
  try {
    node.focus();
  } catch (e) {}
}

module.exports = focusNode;

/***/ }),
/* 70 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * CSS properties which accept numbers but are not in units of "px".
 */

var isUnitlessNumber = {
  animationIterationCount: true,
  borderImageOutset: true,
  borderImageSlice: true,
  borderImageWidth: true,
  boxFlex: true,
  boxFlexGroup: true,
  boxOrdinalGroup: true,
  columnCount: true,
  columns: true,
  flex: true,
  flexGrow: true,
  flexPositive: true,
  flexShrink: true,
  flexNegative: true,
  flexOrder: true,
  gridRow: true,
  gridRowEnd: true,
  gridRowSpan: true,
  gridRowStart: true,
  gridColumn: true,
  gridColumnEnd: true,
  gridColumnSpan: true,
  gridColumnStart: true,
  fontWeight: true,
  lineClamp: true,
  lineHeight: true,
  opacity: true,
  order: true,
  orphans: true,
  tabSize: true,
  widows: true,
  zIndex: true,
  zoom: true,

  // SVG-related properties
  fillOpacity: true,
  floodOpacity: true,
  stopOpacity: true,
  strokeDasharray: true,
  strokeDashoffset: true,
  strokeMiterlimit: true,
  strokeOpacity: true,
  strokeWidth: true
};

/**
 * @param {string} prefix vendor-specific prefix, eg: Webkit
 * @param {string} key style name, eg: transitionDuration
 * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
 * WebkitTransitionDuration
 */
function prefixKey(prefix, key) {
  return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}

/**
 * Support style names that may come passed in prefixed by adding permutations
 * of vendor prefixes.
 */
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];

// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
Object.keys(isUnitlessNumber).forEach(function (prop) {
  prefixes.forEach(function (prefix) {
    isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
  });
});

/**
 * Most style properties can be unset by doing .style[prop] = '' but IE8
 * doesn't like doing that with shorthand properties so for the properties that
 * IE8 breaks on, which are listed here, we instead unset each of the
 * individual properties. See http://bugs.jquery.com/ticket/12385.
 * The 4-value 'clock' properties like margin, padding, border-width seem to
 * behave without any problems. Curiously, list-style works too without any
 * special prodding.
 */
var shorthandPropertyExpansions = {
  background: {
    backgroundAttachment: true,
    backgroundColor: true,
    backgroundImage: true,
    backgroundPositionX: true,
    backgroundPositionY: true,
    backgroundRepeat: true
  },
  backgroundPosition: {
    backgroundPositionX: true,
    backgroundPositionY: true
  },
  border: {
    borderWidth: true,
    borderStyle: true,
    borderColor: true
  },
  borderBottom: {
    borderBottomWidth: true,
    borderBottomStyle: true,
    borderBottomColor: true
  },
  borderLeft: {
    borderLeftWidth: true,
    borderLeftStyle: true,
    borderLeftColor: true
  },
  borderRight: {
    borderRightWidth: true,
    borderRightStyle: true,
    borderRightColor: true
  },
  borderTop: {
    borderTopWidth: true,
    borderTopStyle: true,
    borderTopColor: true
  },
  font: {
    fontStyle: true,
    fontVariant: true,
    fontWeight: true,
    fontSize: true,
    lineHeight: true,
    fontFamily: true
  },
  outline: {
    outlineWidth: true,
    outlineStyle: true,
    outlineColor: true
  }
};

var CSSProperty = {
  isUnitlessNumber: isUnitlessNumber,
  shorthandPropertyExpansions: shorthandPropertyExpansions
};

module.exports = CSSProperty;

/***/ }),
/* 71 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMProperty = __webpack_require__(13);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactInstrumentation = __webpack_require__(7);

var quoteAttributeValueForBrowser = __webpack_require__(138);
var warning = __webpack_require__(1);

var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');
var illegalAttributeNameCache = {};
var validatedAttributeNameCache = {};

function isAttributeNameSafe(attributeName) {
  if (validatedAttributeNameCache.hasOwnProperty(attributeName)) {
    return true;
  }
  if (illegalAttributeNameCache.hasOwnProperty(attributeName)) {
    return false;
  }
  if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
    validatedAttributeNameCache[attributeName] = true;
    return true;
  }
  illegalAttributeNameCache[attributeName] = true;
   true ? warning(false, 'Invalid attribute name: `%s`', attributeName) : void 0;
  return false;
}

function shouldIgnoreValue(propertyInfo, value) {
  return value == null || propertyInfo.hasBooleanValue && !value || propertyInfo.hasNumericValue && isNaN(value) || propertyInfo.hasPositiveNumericValue && value < 1 || propertyInfo.hasOverloadedBooleanValue && value === false;
}

/**
 * Operations for dealing with DOM properties.
 */
var DOMPropertyOperations = {
  /**
   * Creates markup for the ID property.
   *
   * @param {string} id Unescaped ID.
   * @return {string} Markup string.
   */
  createMarkupForID: function (id) {
    return DOMProperty.ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id);
  },

  setAttributeForID: function (node, id) {
    node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id);
  },

  createMarkupForRoot: function () {
    return DOMProperty.ROOT_ATTRIBUTE_NAME + '=""';
  },

  setAttributeForRoot: function (node) {
    node.setAttribute(DOMProperty.ROOT_ATTRIBUTE_NAME, '');
  },

  /**
   * Creates markup for a property.
   *
   * @param {string} name
   * @param {*} value
   * @return {?string} Markup string, or null if the property was invalid.
   */
  createMarkupForProperty: function (name, value) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {
      if (shouldIgnoreValue(propertyInfo, value)) {
        return '';
      }
      var attributeName = propertyInfo.attributeName;
      if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) {
        return attributeName + '=""';
      }
      return attributeName + '=' + quoteAttributeValueForBrowser(value);
    } else if (DOMProperty.isCustomAttribute(name)) {
      if (value == null) {
        return '';
      }
      return name + '=' + quoteAttributeValueForBrowser(value);
    }
    return null;
  },

  /**
   * Creates markup for a custom property.
   *
   * @param {string} name
   * @param {*} value
   * @return {string} Markup string, or empty string if the property was invalid.
   */
  createMarkupForCustomAttribute: function (name, value) {
    if (!isAttributeNameSafe(name) || value == null) {
      return '';
    }
    return name + '=' + quoteAttributeValueForBrowser(value);
  },

  /**
   * Sets the value for a property on a node.
   *
   * @param {DOMElement} node
   * @param {string} name
   * @param {*} value
   */
  setValueForProperty: function (node, name, value) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {
      var mutationMethod = propertyInfo.mutationMethod;
      if (mutationMethod) {
        mutationMethod(node, value);
      } else if (shouldIgnoreValue(propertyInfo, value)) {
        this.deleteValueForProperty(node, name);
        return;
      } else if (propertyInfo.mustUseProperty) {
        // Contrary to `setAttribute`, object properties are properly
        // `toString`ed by IE8/9.
        node[propertyInfo.propertyName] = value;
      } else {
        var attributeName = propertyInfo.attributeName;
        var namespace = propertyInfo.attributeNamespace;
        // `setAttribute` with objects becomes only `[object]` in IE8/9,
        // ('' + value) makes it output the correct toString()-value.
        if (namespace) {
          node.setAttributeNS(namespace, attributeName, '' + value);
        } else if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) {
          node.setAttribute(attributeName, '');
        } else {
          node.setAttribute(attributeName, '' + value);
        }
      }
    } else if (DOMProperty.isCustomAttribute(name)) {
      DOMPropertyOperations.setValueForAttribute(node, name, value);
      return;
    }

    if (true) {
      var payload = {};
      payload[name] = value;
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'update attribute',
        payload: payload
      });
    }
  },

  setValueForAttribute: function (node, name, value) {
    if (!isAttributeNameSafe(name)) {
      return;
    }
    if (value == null) {
      node.removeAttribute(name);
    } else {
      node.setAttribute(name, '' + value);
    }

    if (true) {
      var payload = {};
      payload[name] = value;
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'update attribute',
        payload: payload
      });
    }
  },

  /**
   * Deletes an attributes from a node.
   *
   * @param {DOMElement} node
   * @param {string} name
   */
  deleteValueForAttribute: function (node, name) {
    node.removeAttribute(name);
    if (true) {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'remove attribute',
        payload: name
      });
    }
  },

  /**
   * Deletes the value for a property on a node.
   *
   * @param {DOMElement} node
   * @param {string} name
   */
  deleteValueForProperty: function (node, name) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {
      var mutationMethod = propertyInfo.mutationMethod;
      if (mutationMethod) {
        mutationMethod(node, undefined);
      } else if (propertyInfo.mustUseProperty) {
        var propName = propertyInfo.propertyName;
        if (propertyInfo.hasBooleanValue) {
          node[propName] = false;
        } else {
          node[propName] = '';
        }
      } else {
        node.removeAttribute(propertyInfo.attributeName);
      }
    } else if (DOMProperty.isCustomAttribute(name)) {
      node.removeAttribute(name);
    }

    if (true) {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'remove attribute',
        payload: name
      });
    }
  }
};

module.exports = DOMPropertyOperations;

/***/ }),
/* 72 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';

module.exports = ReactPropTypesSecret;

/***/ }),
/* 73 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var LinkedValueUtils = __webpack_require__(44);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactUpdates = __webpack_require__(10);

var warning = __webpack_require__(1);

var didWarnValueLink = false;
var didWarnValueDefaultValue = false;

function updateOptionsIfPendingUpdateAndMounted() {
  if (this._rootNodeID && this._wrapperState.pendingUpdate) {
    this._wrapperState.pendingUpdate = false;

    var props = this._currentElement.props;
    var value = LinkedValueUtils.getValue(props);

    if (value != null) {
      updateOptions(this, Boolean(props.multiple), value);
    }
  }
}

function getDeclarationErrorAddendum(owner) {
  if (owner) {
    var name = owner.getName();
    if (name) {
      return ' Check the render method of `' + name + '`.';
    }
  }
  return '';
}

var valuePropNames = ['value', 'defaultValue'];

/**
 * Validation function for `value` and `defaultValue`.
 * @private
 */
function checkSelectPropTypes(inst, props) {
  var owner = inst._currentElement._owner;
  LinkedValueUtils.checkPropTypes('select', props, owner);

  if (props.valueLink !== undefined && !didWarnValueLink) {
     true ? warning(false, '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.') : void 0;
    didWarnValueLink = true;
  }

  for (var i = 0; i < valuePropNames.length; i++) {
    var propName = valuePropNames[i];
    if (props[propName] == null) {
      continue;
    }
    var isArray = Array.isArray(props[propName]);
    if (props.multiple && !isArray) {
       true ? warning(false, 'The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum(owner)) : void 0;
    } else if (!props.multiple && isArray) {
       true ? warning(false, 'The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum(owner)) : void 0;
    }
  }
}

/**
 * @param {ReactDOMComponent} inst
 * @param {boolean} multiple
 * @param {*} propValue A stringable (with `multiple`, a list of stringables).
 * @private
 */
function updateOptions(inst, multiple, propValue) {
  var selectedValue, i;
  var options = ReactDOMComponentTree.getNodeFromInstance(inst).options;

  if (multiple) {
    selectedValue = {};
    for (i = 0; i < propValue.length; i++) {
      selectedValue['' + propValue[i]] = true;
    }
    for (i = 0; i < options.length; i++) {
      var selected = selectedValue.hasOwnProperty(options[i].value);
      if (options[i].selected !== selected) {
        options[i].selected = selected;
      }
    }
  } else {
    // Do not set `select.value` as exact behavior isn't consistent across all
    // browsers for all cases.
    selectedValue = '' + propValue;
    for (i = 0; i < options.length; i++) {
      if (options[i].value === selectedValue) {
        options[i].selected = true;
        return;
      }
    }
    if (options.length) {
      options[0].selected = true;
    }
  }
}

/**
 * Implements a <select> host component that allows optionally setting the
 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
 * stringable. If `multiple` is true, the prop must be an array of stringables.
 *
 * If `value` is not supplied (or null/undefined), user actions that change the
 * selected option will trigger updates to the rendered options.
 *
 * If it is supplied (and not null/undefined), the rendered options will not
 * update in response to user actions. Instead, the `value` prop must change in
 * order for the rendered options to update.
 *
 * If `defaultValue` is provided, any options with the supplied values will be
 * selected.
 */
var ReactDOMSelect = {
  getHostProps: function (inst, props) {
    return _assign({}, props, {
      onChange: inst._wrapperState.onChange,
      value: undefined
    });
  },

  mountWrapper: function (inst, props) {
    if (true) {
      checkSelectPropTypes(inst, props);
    }

    var value = LinkedValueUtils.getValue(props);
    inst._wrapperState = {
      pendingUpdate: false,
      initialValue: value != null ? value : props.defaultValue,
      listeners: null,
      onChange: _handleChange.bind(inst),
      wasMultiple: Boolean(props.multiple)
    };

    if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) {
       true ? warning(false, 'Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0;
      didWarnValueDefaultValue = true;
    }
  },

  getSelectValueContext: function (inst) {
    // ReactDOMOption looks at this initial value so the initial generated
    // markup has correct `selected` attributes
    return inst._wrapperState.initialValue;
  },

  postUpdateWrapper: function (inst) {
    var props = inst._currentElement.props;

    // After the initial mount, we control selected-ness manually so don't pass
    // this value down
    inst._wrapperState.initialValue = undefined;

    var wasMultiple = inst._wrapperState.wasMultiple;
    inst._wrapperState.wasMultiple = Boolean(props.multiple);

    var value = LinkedValueUtils.getValue(props);
    if (value != null) {
      inst._wrapperState.pendingUpdate = false;
      updateOptions(inst, Boolean(props.multiple), value);
    } else if (wasMultiple !== Boolean(props.multiple)) {
      // For simplicity, reapply `defaultValue` if `multiple` is toggled.
      if (props.defaultValue != null) {
        updateOptions(inst, Boolean(props.multiple), props.defaultValue);
      } else {
        // Revert the select back to its default unselected state.
        updateOptions(inst, Boolean(props.multiple), props.multiple ? [] : '');
      }
    }
  }
};

function _handleChange(event) {
  var props = this._currentElement.props;
  var returnValue = LinkedValueUtils.executeOnChange(props, event);

  if (this._rootNodeID) {
    this._wrapperState.pendingUpdate = true;
  }
  ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
  return returnValue;
}

module.exports = ReactDOMSelect;

/***/ }),
/* 74 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var ReactCompositeComponent = __webpack_require__(146);
var ReactEmptyComponent = __webpack_require__(76);
var ReactHostComponent = __webpack_require__(77);

var getNextDebugID = __webpack_require__(149);
var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

// To avoid a cyclic dependency, we create the final class in this module
var ReactCompositeComponentWrapper = function (element) {
  this.construct(element);
};

function getDeclarationErrorAddendum(owner) {
  if (owner) {
    var name = owner.getName();
    if (name) {
      return ' Check the render method of `' + name + '`.';
    }
  }
  return '';
}

/**
 * Check if the type reference is a known internal type. I.e. not a user
 * provided composite type.
 *
 * @param {function} type
 * @return {boolean} Returns true if this is a valid internal type.
 */
function isInternalComponentType(type) {
  return typeof type === 'function' && typeof type.prototype !== 'undefined' && typeof type.prototype.mountComponent === 'function' && typeof type.prototype.receiveComponent === 'function';
}

/**
 * Given a ReactNode, create an instance that will actually be mounted.
 *
 * @param {ReactNode} node
 * @param {boolean} shouldHaveDebugID
 * @return {object} A new instance of the element's constructor.
 * @protected
 */
function instantiateReactComponent(node, shouldHaveDebugID) {
  var instance;

  if (node === null || node === false) {
    instance = ReactEmptyComponent.create(instantiateReactComponent);
  } else if (typeof node === 'object') {
    var element = node;
    var type = element.type;
    if (typeof type !== 'function' && typeof type !== 'string') {
      var info = '';
      if (true) {
        if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
          info += ' You likely forgot to export your component from the file ' + "it's defined in.";
        }
      }
      info += getDeclarationErrorAddendum(element._owner);
       true ?  true ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info) : _prodInvariant('130', type == null ? type : typeof type, info) : void 0;
    }

    // Special case string values
    if (typeof element.type === 'string') {
      instance = ReactHostComponent.createInternalComponent(element);
    } else if (isInternalComponentType(element.type)) {
      // This is temporarily available for custom components that are not string
      // representations. I.e. ART. Once those are updated to use the string
      // representation, we can drop this code path.
      instance = new element.type(element);

      // We renamed this. Allow the old name for compat. :(
      if (!instance.getHostNode) {
        instance.getHostNode = instance.getNativeNode;
      }
    } else {
      instance = new ReactCompositeComponentWrapper(element);
    }
  } else if (typeof node === 'string' || typeof node === 'number') {
    instance = ReactHostComponent.createInstanceForText(node);
  } else {
     true ?  true ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : _prodInvariant('131', typeof node) : void 0;
  }

  if (true) {
     true ? warning(typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.getHostNode === 'function' && typeof instance.unmountComponent === 'function', 'Only React Components can be mounted.') : void 0;
  }

  // These two fields are used by the DOM and ART diffing algorithms
  // respectively. Instead of using expandos on components, we should be
  // storing the state needed by the diffing algorithms elsewhere.
  instance._mountIndex = 0;
  instance._mountImage = null;

  if (true) {
    instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0;
  }

  // Internal instances should fully constructed at this point, so they should
  // not get any new fields added to them at this point.
  if (true) {
    if (Object.preventExtensions) {
      Object.preventExtensions(instance);
    }
  }

  return instance;
}

_assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent, {
  _instantiateReactComponent: instantiateReactComponent
});

module.exports = instantiateReactComponent;

/***/ }),
/* 75 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var React = __webpack_require__(16);

var invariant = __webpack_require__(0);

var ReactNodeTypes = {
  HOST: 0,
  COMPOSITE: 1,
  EMPTY: 2,

  getType: function (node) {
    if (node === null || node === false) {
      return ReactNodeTypes.EMPTY;
    } else if (React.isValidElement(node)) {
      if (typeof node.type === 'function') {
        return ReactNodeTypes.COMPOSITE;
      } else {
        return ReactNodeTypes.HOST;
      }
    }
     true ?  true ? invariant(false, 'Unexpected node: %s', node) : _prodInvariant('26', node) : void 0;
  }
};

module.exports = ReactNodeTypes;

/***/ }),
/* 76 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var emptyComponentFactory;

var ReactEmptyComponentInjection = {
  injectEmptyComponentFactory: function (factory) {
    emptyComponentFactory = factory;
  }
};

var ReactEmptyComponent = {
  create: function (instantiate) {
    return emptyComponentFactory(instantiate);
  }
};

ReactEmptyComponent.injection = ReactEmptyComponentInjection;

module.exports = ReactEmptyComponent;

/***/ }),
/* 77 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

var genericComponentClass = null;
var textComponentClass = null;

var ReactHostComponentInjection = {
  // This accepts a class that receives the tag string. This is a catch all
  // that can render any kind of tag.
  injectGenericComponentClass: function (componentClass) {
    genericComponentClass = componentClass;
  },
  // This accepts a text component class that takes the text string to be
  // rendered as props.
  injectTextComponentClass: function (componentClass) {
    textComponentClass = componentClass;
  }
};

/**
 * Get a host internal component class for a specific tag.
 *
 * @param {ReactElement} element The element to create.
 * @return {function} The internal class constructor function.
 */
function createInternalComponent(element) {
  !genericComponentClass ?  true ? invariant(false, 'There is no registered component for the tag %s', element.type) : _prodInvariant('111', element.type) : void 0;
  return new genericComponentClass(element);
}

/**
 * @param {ReactText} text
 * @return {ReactComponent}
 */
function createInstanceForText(text) {
  return new textComponentClass(text);
}

/**
 * @param {ReactComponent} component
 * @return {boolean}
 */
function isTextComponent(component) {
  return component instanceof textComponentClass;
}

var ReactHostComponent = {
  createInternalComponent: createInternalComponent,
  createInstanceForText: createInstanceForText,
  isTextComponent: isTextComponent,
  injection: ReactHostComponentInjection
};

module.exports = ReactHostComponent;

/***/ }),
/* 78 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactCurrentOwner = __webpack_require__(9);
var REACT_ELEMENT_TYPE = __webpack_require__(150);

var getIteratorFn = __webpack_require__(151);
var invariant = __webpack_require__(0);
var KeyEscapeUtils = __webpack_require__(48);
var warning = __webpack_require__(1);

var SEPARATOR = '.';
var SUBSEPARATOR = ':';

/**
 * This is inlined from ReactElement since this file is shared between
 * isomorphic and renderers. We could extract this to a
 *
 */

/**
 * TODO: Test that a single child and an array with one item have the same key
 * pattern.
 */

var didWarnAboutMaps = false;

/**
 * Generate a key string that identifies a component within a set.
 *
 * @param {*} component A component that could contain a manual key.
 * @param {number} index Index that is used if a manual key is not provided.
 * @return {string}
 */
function getComponentKey(component, index) {
  // Do some typechecking here since we call this blindly. We want to ensure
  // that we don't block potential future ES APIs.
  if (component && typeof component === 'object' && component.key != null) {
    // Explicit key
    return KeyEscapeUtils.escape(component.key);
  }
  // Implicit key determined by the index in the set
  return index.toString(36);
}

/**
 * @param {?*} children Children tree container.
 * @param {!string} nameSoFar Name of the key path so far.
 * @param {!function} callback Callback to invoke with each child found.
 * @param {?*} traverseContext Used to pass information throughout the traversal
 * process.
 * @return {!number} The number of children in this subtree.
 */
function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
  var type = typeof children;

  if (type === 'undefined' || type === 'boolean') {
    // All of the above are perceived as null.
    children = null;
  }

  if (children === null || type === 'string' || type === 'number' ||
  // The following is inlined from ReactElement. This means we can optimize
  // some checks. React Fiber also inlines this logic for similar purposes.
  type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) {
    callback(traverseContext, children,
    // If it's the only child, treat the name as if it was wrapped in an array
    // so that it's consistent if the number of children grows.
    nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
    return 1;
  }

  var child;
  var nextName;
  var subtreeCount = 0; // Count of children found in the current subtree.
  var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;

  if (Array.isArray(children)) {
    for (var i = 0; i < children.length; i++) {
      child = children[i];
      nextName = nextNamePrefix + getComponentKey(child, i);
      subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
    }
  } else {
    var iteratorFn = getIteratorFn(children);
    if (iteratorFn) {
      var iterator = iteratorFn.call(children);
      var step;
      if (iteratorFn !== children.entries) {
        var ii = 0;
        while (!(step = iterator.next()).done) {
          child = step.value;
          nextName = nextNamePrefix + getComponentKey(child, ii++);
          subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
        }
      } else {
        if (true) {
          var mapsAsChildrenAddendum = '';
          if (ReactCurrentOwner.current) {
            var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
            if (mapsAsChildrenOwnerName) {
              mapsAsChildrenAddendum = ' Check the render method of `' + mapsAsChildrenOwnerName + '`.';
            }
          }
           true ? warning(didWarnAboutMaps, 'Using Maps as children is not yet fully supported. It is an ' + 'experimental feature that might be removed. Convert it to a ' + 'sequence / iterable of keyed ReactElements instead.%s', mapsAsChildrenAddendum) : void 0;
          didWarnAboutMaps = true;
        }
        // Iterator will provide entry [k,v] tuples rather than values.
        while (!(step = iterator.next()).done) {
          var entry = step.value;
          if (entry) {
            child = entry[1];
            nextName = nextNamePrefix + KeyEscapeUtils.escape(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
            subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
          }
        }
      }
    } else if (type === 'object') {
      var addendum = '';
      if (true) {
        addendum = ' If you meant to render a collection of children, use an array ' + 'instead or wrap the object using createFragment(object) from the ' + 'React add-ons.';
        if (children._isReactElement) {
          addendum = " It looks like you're using an element created by a different " + 'version of React. Make sure to use only one copy of React.';
        }
        if (ReactCurrentOwner.current) {
          var name = ReactCurrentOwner.current.getName();
          if (name) {
            addendum += ' Check the render method of `' + name + '`.';
          }
        }
      }
      var childrenString = String(children);
       true ?  true ? invariant(false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : _prodInvariant('31', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : void 0;
    }
  }

  return subtreeCount;
}

/**
 * Traverses children that are typically specified as `props.children`, but
 * might also be specified through attributes:
 *
 * - `traverseAllChildren(this.props.children, ...)`
 * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
 *
 * The `traverseContext` is an optional argument that is passed through the
 * entire traversal. It can be used to store accumulations or anything else that
 * the callback might find relevant.
 *
 * @param {?*} children Children tree object.
 * @param {!function} callback To invoke upon traversing each child.
 * @param {?*} traverseContext Context for traversal.
 * @return {!number} The number of children in this subtree.
 */
function traverseAllChildren(children, callback, traverseContext) {
  if (children == null) {
    return 0;
  }

  return traverseAllChildrenImpl(children, '', callback, traverseContext);
}

module.exports = traverseAllChildren;

/***/ }),
/* 79 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var emptyFunction = __webpack_require__(8);

/**
 * Upstream version of event listener. Does not take into account specific
 * nature of platform.
 */
var EventListener = {
  /**
   * Listen to DOM events during the bubble phase.
   *
   * @param {DOMEventTarget} target DOM element to register listener on.
   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
   * @param {function} callback Callback function.
   * @return {object} Object with a `remove` method.
   */
  listen: function listen(target, eventType, callback) {
    if (target.addEventListener) {
      target.addEventListener(eventType, callback, false);
      return {
        remove: function remove() {
          target.removeEventListener(eventType, callback, false);
        }
      };
    } else if (target.attachEvent) {
      target.attachEvent('on' + eventType, callback);
      return {
        remove: function remove() {
          target.detachEvent('on' + eventType, callback);
        }
      };
    }
  },

  /**
   * Listen to DOM events during the capture phase.
   *
   * @param {DOMEventTarget} target DOM element to register listener on.
   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
   * @param {function} callback Callback function.
   * @return {object} Object with a `remove` method.
   */
  capture: function capture(target, eventType, callback) {
    if (target.addEventListener) {
      target.addEventListener(eventType, callback, true);
      return {
        remove: function remove() {
          target.removeEventListener(eventType, callback, true);
        }
      };
    } else {
      if (true) {
        console.error('Attempted to listen to events during the capture phase on a ' + 'browser that does not support the capture phase. Your application ' + 'will not receive some events.');
      }
      return {
        remove: emptyFunction
      };
    }
  },

  registerDefault: function registerDefault() {}
};

module.exports = EventListener;

/***/ }),
/* 80 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactDOMSelection = __webpack_require__(163);

var containsNode = __webpack_require__(165);
var focusNode = __webpack_require__(69);
var getActiveElement = __webpack_require__(81);

function isInDocument(node) {
  return containsNode(document.documentElement, node);
}

/**
 * @ReactInputSelection: React input selection module. Based on Selection.js,
 * but modified to be suitable for react and has a couple of bug fixes (doesn't
 * assume buttons have range selections allowed).
 * Input selection module for React.
 */
var ReactInputSelection = {
  hasSelectionCapabilities: function (elem) {
    var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();
    return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true');
  },

  getSelectionInformation: function () {
    var focusedElem = getActiveElement();
    return {
      focusedElem: focusedElem,
      selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem) ? ReactInputSelection.getSelection(focusedElem) : null
    };
  },

  /**
   * @restoreSelection: If any selection information was potentially lost,
   * restore it. This is useful when performing operations that could remove dom
   * nodes and place them back in, resulting in focus being lost.
   */
  restoreSelection: function (priorSelectionInformation) {
    var curFocusedElem = getActiveElement();
    var priorFocusedElem = priorSelectionInformation.focusedElem;
    var priorSelectionRange = priorSelectionInformation.selectionRange;
    if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {
      if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
        ReactInputSelection.setSelection(priorFocusedElem, priorSelectionRange);
      }
      focusNode(priorFocusedElem);
    }
  },

  /**
   * @getSelection: Gets the selection bounds of a focused textarea, input or
   * contentEditable node.
   * -@input: Look up selection bounds of this input
   * -@return {start: selectionStart, end: selectionEnd}
   */
  getSelection: function (input) {
    var selection;

    if ('selectionStart' in input) {
      // Modern browser with input or textarea.
      selection = {
        start: input.selectionStart,
        end: input.selectionEnd
      };
    } else if (document.selection && input.nodeName && input.nodeName.toLowerCase() === 'input') {
      // IE8 input.
      var range = document.selection.createRange();
      // There can only be one selection per document in IE, so it must
      // be in our element.
      if (range.parentElement() === input) {
        selection = {
          start: -range.moveStart('character', -input.value.length),
          end: -range.moveEnd('character', -input.value.length)
        };
      }
    } else {
      // Content editable or old IE textarea.
      selection = ReactDOMSelection.getOffsets(input);
    }

    return selection || { start: 0, end: 0 };
  },

  /**
   * @setSelection: Sets the selection bounds of a textarea or input and focuses
   * the input.
   * -@input     Set selection bounds of this input or textarea
   * -@offsets   Object of same form that is returned from get*
   */
  setSelection: function (input, offsets) {
    var start = offsets.start;
    var end = offsets.end;
    if (end === undefined) {
      end = start;
    }

    if ('selectionStart' in input) {
      input.selectionStart = start;
      input.selectionEnd = Math.min(end, input.value.length);
    } else if (document.selection && input.nodeName && input.nodeName.toLowerCase() === 'input') {
      var range = input.createTextRange();
      range.collapse(true);
      range.moveStart('character', start);
      range.moveEnd('character', end - start);
      range.select();
    } else {
      ReactDOMSelection.setOffsets(input, offsets);
    }
  }
};

module.exports = ReactInputSelection;

/***/ }),
/* 81 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

/* eslint-disable fb-www/typeof-undefined */

/**
 * Same as document.activeElement but wraps in a try-catch block. In IE it is
 * not safe to call document.activeElement if there is nothing focused.
 *
 * The activeElement will be null only if the document or document body is not
 * yet defined.
 *
 * @param {?DOMDocument} doc Defaults to current document.
 * @return {?DOMElement}
 */
function getActiveElement(doc) /*?DOMElement*/{
  doc = doc || (typeof document !== 'undefined' ? document : undefined);
  if (typeof doc === 'undefined') {
    return null;
  }
  try {
    return doc.activeElement || doc.body;
  } catch (e) {
    return doc.body;
  }
}

module.exports = getActiveElement;

/***/ }),
/* 82 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var DOMLazyTree = __webpack_require__(19);
var DOMProperty = __webpack_require__(13);
var React = __webpack_require__(16);
var ReactBrowserEventEmitter = __webpack_require__(33);
var ReactCurrentOwner = __webpack_require__(9);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactDOMContainerInfo = __webpack_require__(180);
var ReactDOMFeatureFlags = __webpack_require__(181);
var ReactFeatureFlags = __webpack_require__(64);
var ReactInstanceMap = __webpack_require__(23);
var ReactInstrumentation = __webpack_require__(7);
var ReactMarkupChecksum = __webpack_require__(182);
var ReactReconciler = __webpack_require__(18);
var ReactUpdateQueue = __webpack_require__(49);
var ReactUpdates = __webpack_require__(10);

var emptyObject = __webpack_require__(27);
var instantiateReactComponent = __webpack_require__(74);
var invariant = __webpack_require__(0);
var setInnerHTML = __webpack_require__(31);
var shouldUpdateReactComponent = __webpack_require__(47);
var warning = __webpack_require__(1);

var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
var ROOT_ATTR_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME;

var ELEMENT_NODE_TYPE = 1;
var DOC_NODE_TYPE = 9;
var DOCUMENT_FRAGMENT_NODE_TYPE = 11;

var instancesByReactRootID = {};

/**
 * Finds the index of the first character
 * that's not common between the two given strings.
 *
 * @return {number} the index of the character where the strings diverge
 */
function firstDifferenceIndex(string1, string2) {
  var minLen = Math.min(string1.length, string2.length);
  for (var i = 0; i < minLen; i++) {
    if (string1.charAt(i) !== string2.charAt(i)) {
      return i;
    }
  }
  return string1.length === string2.length ? -1 : minLen;
}

/**
 * @param {DOMElement|DOMDocument} container DOM element that may contain
 * a React component
 * @return {?*} DOM element that may have the reactRoot ID, or null.
 */
function getReactRootElementInContainer(container) {
  if (!container) {
    return null;
  }

  if (container.nodeType === DOC_NODE_TYPE) {
    return container.documentElement;
  } else {
    return container.firstChild;
  }
}

function internalGetID(node) {
  // If node is something like a window, document, or text node, none of
  // which support attributes or a .getAttribute method, gracefully return
  // the empty string, as if the attribute were missing.
  return node.getAttribute && node.getAttribute(ATTR_NAME) || '';
}

/**
 * Mounts this component and inserts it into the DOM.
 *
 * @param {ReactComponent} componentInstance The instance to mount.
 * @param {DOMElement} container DOM element to mount into.
 * @param {ReactReconcileTransaction} transaction
 * @param {boolean} shouldReuseMarkup If true, do not insert markup
 */
function mountComponentIntoNode(wrapperInstance, container, transaction, shouldReuseMarkup, context) {
  var markerName;
  if (ReactFeatureFlags.logTopLevelRenders) {
    var wrappedElement = wrapperInstance._currentElement.props.child;
    var type = wrappedElement.type;
    markerName = 'React mount: ' + (typeof type === 'string' ? type : type.displayName || type.name);
    console.time(markerName);
  }

  var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 /* parentDebugID */
  );

  if (markerName) {
    console.timeEnd(markerName);
  }

  wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance;
  ReactMount._mountImageIntoNode(markup, container, wrapperInstance, shouldReuseMarkup, transaction);
}

/**
 * Batched mount.
 *
 * @param {ReactComponent} componentInstance The instance to mount.
 * @param {DOMElement} container DOM element to mount into.
 * @param {boolean} shouldReuseMarkup If true, do not insert markup
 */
function batchedMountComponentIntoNode(componentInstance, container, shouldReuseMarkup, context) {
  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
  /* useCreateElement */
  !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement);
  transaction.perform(mountComponentIntoNode, null, componentInstance, container, transaction, shouldReuseMarkup, context);
  ReactUpdates.ReactReconcileTransaction.release(transaction);
}

/**
 * Unmounts a component and removes it from the DOM.
 *
 * @param {ReactComponent} instance React component instance.
 * @param {DOMElement} container DOM element to unmount from.
 * @final
 * @internal
 * @see {ReactMount.unmountComponentAtNode}
 */
function unmountComponentFromNode(instance, container, safely) {
  if (true) {
    ReactInstrumentation.debugTool.onBeginFlush();
  }
  ReactReconciler.unmountComponent(instance, safely);
  if (true) {
    ReactInstrumentation.debugTool.onEndFlush();
  }

  if (container.nodeType === DOC_NODE_TYPE) {
    container = container.documentElement;
  }

  // http://jsperf.com/emptying-a-node
  while (container.lastChild) {
    container.removeChild(container.lastChild);
  }
}

/**
 * True if the supplied DOM node has a direct React-rendered child that is
 * not a React root element. Useful for warning in `render`,
 * `unmountComponentAtNode`, etc.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM element contains a direct child that was
 * rendered by React but is not a root element.
 * @internal
 */
function hasNonRootReactChild(container) {
  var rootEl = getReactRootElementInContainer(container);
  if (rootEl) {
    var inst = ReactDOMComponentTree.getInstanceFromNode(rootEl);
    return !!(inst && inst._hostParent);
  }
}

/**
 * True if the supplied DOM node is a React DOM element and
 * it has been rendered by another copy of React.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM has been rendered by another copy of React
 * @internal
 */
function nodeIsRenderedByOtherInstance(container) {
  var rootEl = getReactRootElementInContainer(container);
  return !!(rootEl && isReactNode(rootEl) && !ReactDOMComponentTree.getInstanceFromNode(rootEl));
}

/**
 * True if the supplied DOM node is a valid node element.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM is a valid DOM node.
 * @internal
 */
function isValidContainer(node) {
  return !!(node && (node.nodeType === ELEMENT_NODE_TYPE || node.nodeType === DOC_NODE_TYPE || node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE));
}

/**
 * True if the supplied DOM node is a valid React node element.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM is a valid React DOM node.
 * @internal
 */
function isReactNode(node) {
  return isValidContainer(node) && (node.hasAttribute(ROOT_ATTR_NAME) || node.hasAttribute(ATTR_NAME));
}

function getHostRootInstanceInContainer(container) {
  var rootEl = getReactRootElementInContainer(container);
  var prevHostInstance = rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl);
  return prevHostInstance && !prevHostInstance._hostParent ? prevHostInstance : null;
}

function getTopLevelWrapperInContainer(container) {
  var root = getHostRootInstanceInContainer(container);
  return root ? root._hostContainerInfo._topLevelWrapper : null;
}

/**
 * Temporary (?) hack so that we can store all top-level pending updates on
 * composites instead of having to worry about different types of components
 * here.
 */
var topLevelRootCounter = 1;
var TopLevelWrapper = function () {
  this.rootID = topLevelRootCounter++;
};
TopLevelWrapper.prototype.isReactComponent = {};
if (true) {
  TopLevelWrapper.displayName = 'TopLevelWrapper';
}
TopLevelWrapper.prototype.render = function () {
  return this.props.child;
};
TopLevelWrapper.isReactTopLevelWrapper = true;

/**
 * Mounting is the process of initializing a React component by creating its
 * representative DOM elements and inserting them into a supplied `container`.
 * Any prior content inside `container` is destroyed in the process.
 *
 *   ReactMount.render(
 *     component,
 *     document.getElementById('container')
 *   );
 *
 *   <div id="container">                   <-- Supplied `container`.
 *     <div data-reactid=".3">              <-- Rendered reactRoot of React
 *       // ...                                 component.
 *     </div>
 *   </div>
 *
 * Inside of `container`, the first element rendered is the "reactRoot".
 */
var ReactMount = {
  TopLevelWrapper: TopLevelWrapper,

  /**
   * Used by devtools. The keys are not important.
   */
  _instancesByReactRootID: instancesByReactRootID,

  /**
   * This is a hook provided to support rendering React components while
   * ensuring that the apparent scroll position of its `container` does not
   * change.
   *
   * @param {DOMElement} container The `container` being rendered into.
   * @param {function} renderCallback This must be called once to do the render.
   */
  scrollMonitor: function (container, renderCallback) {
    renderCallback();
  },

  /**
   * Take a component that's already mounted into the DOM and replace its props
   * @param {ReactComponent} prevComponent component instance already in the DOM
   * @param {ReactElement} nextElement component instance to render
   * @param {DOMElement} container container to render into
   * @param {?function} callback function triggered on completion
   */
  _updateRootComponent: function (prevComponent, nextElement, nextContext, container, callback) {
    ReactMount.scrollMonitor(container, function () {
      ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement, nextContext);
      if (callback) {
        ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
      }
    });

    return prevComponent;
  },

  /**
   * Render a new component into the DOM. Hooked by hooks!
   *
   * @param {ReactElement} nextElement element to render
   * @param {DOMElement} container container to render into
   * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
   * @return {ReactComponent} nextComponent
   */
  _renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) {
    // Various parts of our code (such as ReactCompositeComponent's
    // _renderValidatedComponent) assume that calls to render aren't nested;
    // verify that that's the case.
     true ? warning(ReactCurrentOwner.current == null, '_renderNewRootComponent(): Render methods should be a pure function ' + 'of props and state; triggering nested component updates from ' + 'render is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName() || 'ReactCompositeComponent') : void 0;

    !isValidContainer(container) ?  true ? invariant(false, '_registerComponent(...): Target container is not a DOM element.') : _prodInvariant('37') : void 0;

    ReactBrowserEventEmitter.ensureScrollValueMonitoring();
    var componentInstance = instantiateReactComponent(nextElement, false);

    // The initial render is synchronous but any updates that happen during
    // rendering, in componentWillMount or componentDidMount, will be batched
    // according to the current batching strategy.

    ReactUpdates.batchedUpdates(batchedMountComponentIntoNode, componentInstance, container, shouldReuseMarkup, context);

    var wrapperID = componentInstance._instance.rootID;
    instancesByReactRootID[wrapperID] = componentInstance;

    return componentInstance;
  },

  /**
   * Renders a React component into the DOM in the supplied `container`.
   *
   * If the React component was previously rendered into `container`, this will
   * perform an update on it and only mutate the DOM as necessary to reflect the
   * latest React component.
   *
   * @param {ReactComponent} parentComponent The conceptual parent of this render tree.
   * @param {ReactElement} nextElement Component element to render.
   * @param {DOMElement} container DOM element to render into.
   * @param {?function} callback function triggered on completion
   * @return {ReactComponent} Component instance rendered in `container`.
   */
  renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
    !(parentComponent != null && ReactInstanceMap.has(parentComponent)) ?  true ? invariant(false, 'parentComponent must be a valid React Component') : _prodInvariant('38') : void 0;
    return ReactMount._renderSubtreeIntoContainer(parentComponent, nextElement, container, callback);
  },

  _renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
    ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render');
    !React.isValidElement(nextElement) ?  true ? invariant(false, 'ReactDOM.render(): Invalid component element.%s', typeof nextElement === 'string' ? " Instead of passing a string like 'div', pass " + "React.createElement('div') or <div />." : typeof nextElement === 'function' ? ' Instead of passing a class like Foo, pass ' + 'React.createElement(Foo) or <Foo />.' : // Check if it quacks like an element
    nextElement != null && nextElement.props !== undefined ? ' This may be caused by unintentionally loading two independent ' + 'copies of React.' : '') : _prodInvariant('39', typeof nextElement === 'string' ? " Instead of passing a string like 'div', pass " + "React.createElement('div') or <div />." : typeof nextElement === 'function' ? ' Instead of passing a class like Foo, pass ' + 'React.createElement(Foo) or <Foo />.' : nextElement != null && nextElement.props !== undefined ? ' This may be caused by unintentionally loading two independent ' + 'copies of React.' : '') : void 0;

     true ? warning(!container || !container.tagName || container.tagName.toUpperCase() !== 'BODY', 'render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.') : void 0;

    var nextWrappedElement = React.createElement(TopLevelWrapper, {
      child: nextElement
    });

    var nextContext;
    if (parentComponent) {
      var parentInst = ReactInstanceMap.get(parentComponent);
      nextContext = parentInst._processChildContext(parentInst._context);
    } else {
      nextContext = emptyObject;
    }

    var prevComponent = getTopLevelWrapperInContainer(container);

    if (prevComponent) {
      var prevWrappedElement = prevComponent._currentElement;
      var prevElement = prevWrappedElement.props.child;
      if (shouldUpdateReactComponent(prevElement, nextElement)) {
        var publicInst = prevComponent._renderedComponent.getPublicInstance();
        var updatedCallback = callback && function () {
          callback.call(publicInst);
        };
        ReactMount._updateRootComponent(prevComponent, nextWrappedElement, nextContext, container, updatedCallback);
        return publicInst;
      } else {
        ReactMount.unmountComponentAtNode(container);
      }
    }

    var reactRootElement = getReactRootElementInContainer(container);
    var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement);
    var containerHasNonRootReactChild = hasNonRootReactChild(container);

    if (true) {
       true ? warning(!containerHasNonRootReactChild, 'render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and render the new components instead of calling ReactDOM.render.') : void 0;

      if (!containerHasReactMarkup || reactRootElement.nextSibling) {
        var rootElementSibling = reactRootElement;
        while (rootElementSibling) {
          if (internalGetID(rootElementSibling)) {
             true ? warning(false, 'render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.') : void 0;
            break;
          }
          rootElementSibling = rootElementSibling.nextSibling;
        }
      }
    }

    var shouldReuseMarkup = containerHasReactMarkup && !prevComponent && !containerHasNonRootReactChild;
    var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)._renderedComponent.getPublicInstance();
    if (callback) {
      callback.call(component);
    }
    return component;
  },

  /**
   * Renders a React component into the DOM in the supplied `container`.
   * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.render
   *
   * If the React component was previously rendered into `container`, this will
   * perform an update on it and only mutate the DOM as necessary to reflect the
   * latest React component.
   *
   * @param {ReactElement} nextElement Component element to render.
   * @param {DOMElement} container DOM element to render into.
   * @param {?function} callback function triggered on completion
   * @return {ReactComponent} Component instance rendered in `container`.
   */
  render: function (nextElement, container, callback) {
    return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
  },

  /**
   * Unmounts and destroys the React component rendered in the `container`.
   * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.unmountcomponentatnode
   *
   * @param {DOMElement} container DOM element containing a React component.
   * @return {boolean} True if a component was found in and unmounted from
   *                   `container`
   */
  unmountComponentAtNode: function (container) {
    // Various parts of our code (such as ReactCompositeComponent's
    // _renderValidatedComponent) assume that calls to render aren't nested;
    // verify that that's the case. (Strictly speaking, unmounting won't cause a
    // render but we still don't expect to be in a render call here.)
     true ? warning(ReactCurrentOwner.current == null, 'unmountComponentAtNode(): Render methods should be a pure function ' + 'of props and state; triggering nested component updates from render ' + 'is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName() || 'ReactCompositeComponent') : void 0;

    !isValidContainer(container) ?  true ? invariant(false, 'unmountComponentAtNode(...): Target container is not a DOM element.') : _prodInvariant('40') : void 0;

    if (true) {
       true ? warning(!nodeIsRenderedByOtherInstance(container), "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by another copy of React.') : void 0;
    }

    var prevComponent = getTopLevelWrapperInContainer(container);
    if (!prevComponent) {
      // Check if the node being unmounted was rendered by React, but isn't a
      // root node.
      var containerHasNonRootReactChild = hasNonRootReactChild(container);

      // Check if the container itself is a React root node.
      var isContainerReactRoot = container.nodeType === 1 && container.hasAttribute(ROOT_ATTR_NAME);

      if (true) {
         true ? warning(!containerHasNonRootReactChild, "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by React and is not a top-level container. %s', isContainerReactRoot ? 'You may have accidentally passed in a React root node instead ' + 'of its container.' : 'Instead, have the parent component update its state and ' + 'rerender in order to remove this component.') : void 0;
      }

      return false;
    }
    delete instancesByReactRootID[prevComponent._instance.rootID];
    ReactUpdates.batchedUpdates(unmountComponentFromNode, prevComponent, container, false);
    return true;
  },

  _mountImageIntoNode: function (markup, container, instance, shouldReuseMarkup, transaction) {
    !isValidContainer(container) ?  true ? invariant(false, 'mountComponentIntoNode(...): Target container is not valid.') : _prodInvariant('41') : void 0;

    if (shouldReuseMarkup) {
      var rootElement = getReactRootElementInContainer(container);
      if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) {
        ReactDOMComponentTree.precacheNode(instance, rootElement);
        return;
      } else {
        var checksum = rootElement.getAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
        rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);

        var rootMarkup = rootElement.outerHTML;
        rootElement.setAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME, checksum);

        var normalizedMarkup = markup;
        if (true) {
          // because rootMarkup is retrieved from the DOM, various normalizations
          // will have occurred which will not be present in `markup`. Here,
          // insert markup into a <div> or <iframe> depending on the container
          // type to perform the same normalizations before comparing.
          var normalizer;
          if (container.nodeType === ELEMENT_NODE_TYPE) {
            normalizer = document.createElement('div');
            normalizer.innerHTML = markup;
            normalizedMarkup = normalizer.innerHTML;
          } else {
            normalizer = document.createElement('iframe');
            document.body.appendChild(normalizer);
            normalizer.contentDocument.write(markup);
            normalizedMarkup = normalizer.contentDocument.documentElement.outerHTML;
            document.body.removeChild(normalizer);
          }
        }

        var diffIndex = firstDifferenceIndex(normalizedMarkup, rootMarkup);
        var difference = ' (client) ' + normalizedMarkup.substring(diffIndex - 20, diffIndex + 20) + '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20);

        !(container.nodeType !== DOC_NODE_TYPE) ?  true ? invariant(false, 'You\'re trying to render a component to the document using server rendering but the checksum was invalid. This usually means you rendered a different component type or props on the client from the one on the server, or your render() methods are impure. React cannot handle this case due to cross-browser quirks by rendering at the document root. You should look for environment dependent code in your components and ensure the props are the same client and server side:\n%s', difference) : _prodInvariant('42', difference) : void 0;

        if (true) {
           true ? warning(false, 'React attempted to reuse markup in a container but the ' + 'checksum was invalid. This generally means that you are ' + 'using server rendering and the markup generated on the ' + 'server was not what the client was expecting. React injected ' + 'new markup to compensate which works but you have lost many ' + 'of the benefits of server rendering. Instead, figure out ' + 'why the markup being generated is different on the client ' + 'or server:\n%s', difference) : void 0;
        }
      }
    }

    !(container.nodeType !== DOC_NODE_TYPE) ?  true ? invariant(false, 'You\'re trying to render a component to the document but you didn\'t use server rendering. We can\'t do this without using server rendering due to cross-browser quirks. See ReactDOMServer.renderToString() for server rendering.') : _prodInvariant('43') : void 0;

    if (transaction.useCreateElement) {
      while (container.lastChild) {
        container.removeChild(container.lastChild);
      }
      DOMLazyTree.insertTreeBefore(container, markup, null);
    } else {
      setInnerHTML(container, markup);
      ReactDOMComponentTree.precacheNode(instance, container.firstChild);
    }

    if (true) {
      var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild);
      if (hostNode._debugID !== 0) {
        ReactInstrumentation.debugTool.onHostOperation({
          instanceID: hostNode._debugID,
          type: 'mount',
          payload: markup.toString()
        });
      }
    }
  }
};

module.exports = ReactMount;

/***/ }),
/* 83 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactNodeTypes = __webpack_require__(75);

function getHostComponentFromComposite(inst) {
  var type;

  while ((type = inst._renderedNodeType) === ReactNodeTypes.COMPOSITE) {
    inst = inst._renderedComponent;
  }

  if (type === ReactNodeTypes.HOST) {
    return inst._renderedComponent;
  } else if (type === ReactNodeTypes.EMPTY) {
    return null;
  }
}

module.exports = getHostComponentFromComposite;

/***/ }),
/* 84 */
/***/ (function(module, exports, __webpack_require__) {

var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
  Copyright (c) 2016 Jed Watson.
  Licensed under the MIT License (MIT), see
  http://jedwatson.github.io/classnames
*/
/* global define */

(function () {
    'use strict';

    var hasOwn = {}.hasOwnProperty;

    function classNames () {
        var classes = [];

        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(' ');
    }

    if (typeof module !== 'undefined' && module.exports) {
        module.exports = classNames;
    } else if (true) {
        // register as 'classnames', consistent with npm package name
        !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
            return classNames;
        }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
                __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
    } else {
        window.classNames = classNames;
    }
}());


/***/ }),
/* 85 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */



var emptyFunction = __webpack_require__(8);
var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);
var assign = __webpack_require__(3);

var ReactPropTypesSecret = __webpack_require__(58);
var checkPropTypes = __webpack_require__(99);

module.exports = function(isValidElement, throwOnDirectAccess) {
  /* global Symbol */
  var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
  var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.

  /**
   * Returns the iterator method function contained on the iterable object.
   *
   * Be sure to invoke the function with the iterable as context:
   *
   *     var iteratorFn = getIteratorFn(myIterable);
   *     if (iteratorFn) {
   *       var iterator = iteratorFn.call(myIterable);
   *       ...
   *     }
   *
   * @param {?object} maybeIterable
   * @return {?function}
   */
  function getIteratorFn(maybeIterable) {
    var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
    if (typeof iteratorFn === 'function') {
      return iteratorFn;
    }
  }

  /**
   * Collection of methods that allow declaration and validation of props that are
   * supplied to React components. Example usage:
   *
   *   var Props = require('ReactPropTypes');
   *   var MyArticle = React.createClass({
   *     propTypes: {
   *       // An optional string prop named "description".
   *       description: Props.string,
   *
   *       // A required enum prop named "category".
   *       category: Props.oneOf(['News','Photos']).isRequired,
   *
   *       // A prop named "dialog" that requires an instance of Dialog.
   *       dialog: Props.instanceOf(Dialog).isRequired
   *     },
   *     render: function() { ... }
   *   });
   *
   * A more formal specification of how these methods are used:
   *
   *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
   *   decl := ReactPropTypes.{type}(.isRequired)?
   *
   * Each and every declaration produces a function with the same signature. This
   * allows the creation of custom validation functions. For example:
   *
   *  var MyLink = React.createClass({
   *    propTypes: {
   *      // An optional string or URI prop named "href".
   *      href: function(props, propName, componentName) {
   *        var propValue = props[propName];
   *        if (propValue != null && typeof propValue !== 'string' &&
   *            !(propValue instanceof URI)) {
   *          return new Error(
   *            'Expected a string or an URI for ' + propName + ' in ' +
   *            componentName
   *          );
   *        }
   *      }
   *    },
   *    render: function() {...}
   *  });
   *
   * @internal
   */

  var ANONYMOUS = '<<anonymous>>';

  // Important!
  // Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
  var ReactPropTypes = {
    array: createPrimitiveTypeChecker('array'),
    bool: createPrimitiveTypeChecker('boolean'),
    func: createPrimitiveTypeChecker('function'),
    number: createPrimitiveTypeChecker('number'),
    object: createPrimitiveTypeChecker('object'),
    string: createPrimitiveTypeChecker('string'),
    symbol: createPrimitiveTypeChecker('symbol'),

    any: createAnyTypeChecker(),
    arrayOf: createArrayOfTypeChecker,
    element: createElementTypeChecker(),
    instanceOf: createInstanceTypeChecker,
    node: createNodeChecker(),
    objectOf: createObjectOfTypeChecker,
    oneOf: createEnumTypeChecker,
    oneOfType: createUnionTypeChecker,
    shape: createShapeTypeChecker,
    exact: createStrictShapeTypeChecker,
  };

  /**
   * inlined Object.is polyfill to avoid requiring consumers ship their own
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
   */
  /*eslint-disable no-self-compare*/
  function is(x, y) {
    // SameValue algorithm
    if (x === y) {
      // Steps 1-5, 7-10
      // Steps 6.b-6.e: +0 != -0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // Step 6.a: NaN == NaN
      return x !== x && y !== y;
    }
  }
  /*eslint-enable no-self-compare*/

  /**
   * We use an Error-like object for backward compatibility as people may call
   * PropTypes directly and inspect their output. However, we don't use real
   * Errors anymore. We don't inspect their stack anyway, and creating them
   * is prohibitively expensive if they are created too often, such as what
   * happens in oneOfType() for any type before the one that matched.
   */
  function PropTypeError(message) {
    this.message = message;
    this.stack = '';
  }
  // Make `instanceof Error` still work for returned errors.
  PropTypeError.prototype = Error.prototype;

  function createChainableTypeChecker(validate) {
    if (true) {
      var manualPropTypeCallCache = {};
      var manualPropTypeWarningCount = 0;
    }
    function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
      componentName = componentName || ANONYMOUS;
      propFullName = propFullName || propName;

      if (secret !== ReactPropTypesSecret) {
        if (throwOnDirectAccess) {
          // New behavior only for users of `prop-types` package
          invariant(
            false,
            '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 if ("test" !== 'production' && typeof console !== 'undefined') {
          // Old behavior for people using React.PropTypes
          var cacheKey = componentName + ':' + propName;
          if (
            !manualPropTypeCallCache[cacheKey] &&
            // Avoid spamming the console because they are often not actionable except for lib authors
            manualPropTypeWarningCount < 3
          ) {
            warning(
              false,
              'You are manually calling a React.PropTypes validation ' +
              'function for the `%s` prop on `%s`. This is deprecated ' +
              'and will throw in the standalone `prop-types` package. ' +
              'You may be seeing this warning due to a third-party PropTypes ' +
              'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.',
              propFullName,
              componentName
            );
            manualPropTypeCallCache[cacheKey] = true;
            manualPropTypeWarningCount++;
          }
        }
      }
      if (props[propName] == null) {
        if (isRequired) {
          if (props[propName] === null) {
            return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
          }
          return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
        }
        return null;
      } else {
        return validate(props, propName, componentName, location, propFullName);
      }
    }

    var chainedCheckType = checkType.bind(null, false);
    chainedCheckType.isRequired = checkType.bind(null, true);

    return chainedCheckType;
  }

  function createPrimitiveTypeChecker(expectedType) {
    function validate(props, propName, componentName, location, propFullName, secret) {
      var propValue = props[propName];
      var propType = getPropType(propValue);
      if (propType !== expectedType) {
        // `propValue` being instance of, say, date/regexp, pass the 'object'
        // check, but we can offer a more precise error message here rather than
        // 'of type `object`'.
        var preciseType = getPreciseType(propValue);

        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createAnyTypeChecker() {
    return createChainableTypeChecker(emptyFunction.thatReturnsNull);
  }

  function createArrayOfTypeChecker(typeChecker) {
    function validate(props, propName, componentName, location, propFullName) {
      if (typeof typeChecker !== 'function') {
        return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
      }
      var propValue = props[propName];
      if (!Array.isArray(propValue)) {
        var propType = getPropType(propValue);
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
      }
      for (var i = 0; i < propValue.length; i++) {
        var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
        if (error instanceof Error) {
          return error;
        }
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createElementTypeChecker() {
    function validate(props, propName, componentName, location, propFullName) {
      var propValue = props[propName];
      if (!isValidElement(propValue)) {
        var propType = getPropType(propValue);
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createInstanceTypeChecker(expectedClass) {
    function validate(props, propName, componentName, location, propFullName) {
      if (!(props[propName] instanceof expectedClass)) {
        var expectedClassName = expectedClass.name || ANONYMOUS;
        var actualClassName = getClassName(props[propName]);
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createEnumTypeChecker(expectedValues) {
    if (!Array.isArray(expectedValues)) {
       true ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
      return emptyFunction.thatReturnsNull;
    }

    function validate(props, propName, componentName, location, propFullName) {
      var propValue = props[propName];
      for (var i = 0; i < expectedValues.length; i++) {
        if (is(propValue, expectedValues[i])) {
          return null;
        }
      }

      var valuesString = JSON.stringify(expectedValues);
      return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
    }
    return createChainableTypeChecker(validate);
  }

  function createObjectOfTypeChecker(typeChecker) {
    function validate(props, propName, componentName, location, propFullName) {
      if (typeof typeChecker !== 'function') {
        return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
      }
      var propValue = props[propName];
      var propType = getPropType(propValue);
      if (propType !== 'object') {
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
      }
      for (var key in propValue) {
        if (propValue.hasOwnProperty(key)) {
          var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
          if (error instanceof Error) {
            return error;
          }
        }
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createUnionTypeChecker(arrayOfTypeCheckers) {
    if (!Array.isArray(arrayOfTypeCheckers)) {
       true ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
      return emptyFunction.thatReturnsNull;
    }

    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
      var checker = arrayOfTypeCheckers[i];
      if (typeof checker !== 'function') {
        warning(
          false,
          'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
          'received %s at index %s.',
          getPostfixForTypeWarning(checker),
          i
        );
        return emptyFunction.thatReturnsNull;
      }
    }

    function validate(props, propName, componentName, location, propFullName) {
      for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
        var checker = arrayOfTypeCheckers[i];
        if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
          return null;
        }
      }

      return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
    }
    return createChainableTypeChecker(validate);
  }

  function createNodeChecker() {
    function validate(props, propName, componentName, location, propFullName) {
      if (!isNode(props[propName])) {
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createShapeTypeChecker(shapeTypes) {
    function validate(props, propName, componentName, location, propFullName) {
      var propValue = props[propName];
      var propType = getPropType(propValue);
      if (propType !== 'object') {
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
      }
      for (var key in shapeTypes) {
        var checker = shapeTypes[key];
        if (!checker) {
          continue;
        }
        var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
        if (error) {
          return error;
        }
      }
      return null;
    }
    return createChainableTypeChecker(validate);
  }

  function createStrictShapeTypeChecker(shapeTypes) {
    function validate(props, propName, componentName, location, propFullName) {
      var propValue = props[propName];
      var propType = getPropType(propValue);
      if (propType !== 'object') {
        return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
      }
      // We need to check all keys in case some are required but missing from
      // props.
      var allKeys = assign({}, props[propName], shapeTypes);
      for (var key in allKeys) {
        var checker = shapeTypes[key];
        if (!checker) {
          return new PropTypeError(
            'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
            '\nBad object: ' + JSON.stringify(props[propName], null, '  ') +
            '\nValid keys: ' +  JSON.stringify(Object.keys(shapeTypes), null, '  ')
          );
        }
        var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
        if (error) {
          return error;
        }
      }
      return null;
    }

    return createChainableTypeChecker(validate);
  }

  function isNode(propValue) {
    switch (typeof propValue) {
      case 'number':
      case 'string':
      case 'undefined':
        return true;
      case 'boolean':
        return !propValue;
      case 'object':
        if (Array.isArray(propValue)) {
          return propValue.every(isNode);
        }
        if (propValue === null || isValidElement(propValue)) {
          return true;
        }

        var iteratorFn = getIteratorFn(propValue);
        if (iteratorFn) {
          var iterator = iteratorFn.call(propValue);
          var step;
          if (iteratorFn !== propValue.entries) {
            while (!(step = iterator.next()).done) {
              if (!isNode(step.value)) {
                return false;
              }
            }
          } else {
            // Iterator will provide entry [k,v] tuples rather than values.
            while (!(step = iterator.next()).done) {
              var entry = step.value;
              if (entry) {
                if (!isNode(entry[1])) {
                  return false;
                }
              }
            }
          }
        } else {
          return false;
        }

        return true;
      default:
        return false;
    }
  }

  function isSymbol(propType, propValue) {
    // Native Symbol.
    if (propType === 'symbol') {
      return true;
    }

    // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
    if (propValue['@@toStringTag'] === 'Symbol') {
      return true;
    }

    // Fallback for non-spec compliant Symbols which are polyfilled.
    if (typeof Symbol === 'function' && propValue instanceof Symbol) {
      return true;
    }

    return false;
  }

  // Equivalent of `typeof` but with special handling for array and regexp.
  function getPropType(propValue) {
    var propType = typeof propValue;
    if (Array.isArray(propValue)) {
      return 'array';
    }
    if (propValue instanceof RegExp) {
      // Old webkits (at least until Android 4.0) return 'function' rather than
      // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
      // passes PropTypes.object.
      return 'object';
    }
    if (isSymbol(propType, propValue)) {
      return 'symbol';
    }
    return propType;
  }

  // This handles more types than `getPropType`. Only used for error messages.
  // See `createPrimitiveTypeChecker`.
  function getPreciseType(propValue) {
    if (typeof propValue === 'undefined' || propValue === null) {
      return '' + propValue;
    }
    var propType = getPropType(propValue);
    if (propType === 'object') {
      if (propValue instanceof Date) {
        return 'date';
      } else if (propValue instanceof RegExp) {
        return 'regexp';
      }
    }
    return propType;
  }

  // Returns a string that is postfixed to a warning about an invalid type.
  // For example, "undefined" or "of type array"
  function getPostfixForTypeWarning(value) {
    var type = getPreciseType(value);
    switch (type) {
      case 'array':
      case 'object':
        return 'an ' + type;
      case 'boolean':
      case 'date':
      case 'regexp':
        return 'a ' + type;
      default:
        return type;
    }
  }

  // Returns class name of the object, if any.
  function getClassName(propValue) {
    if (!propValue.constructor || !propValue.constructor.name) {
      return ANONYMOUS;
    }
    return propValue.constructor.name;
  }

  ReactPropTypes.checkPropTypes = checkPropTypes;
  ReactPropTypes.PropTypes = ReactPropTypes;

  return ReactPropTypes;
};


/***/ }),
/* 86 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.SoundOffIcon = exports.SoundOnIcon = exports.NextIcon = exports.PreviousIcon = exports.PauseIcon = exports.PlayIcon = undefined;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Play
 */
var PlayIcon = exports.PlayIcon = function PlayIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon PlayIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement("polygon", { className: "Icon-shape", points: "24 92 24 7 100 49.4955227" })
  );
};

/**
 * Pause
 */
var PauseIcon = exports.PauseIcon = function PauseIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon PauseIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement(
      "g",
      { className: "Icon-group" },
      _react2.default.createElement("rect", { className: "Icon-shape", x: "58", y: "11", width: "21", height: "78" }),
      _react2.default.createElement("rect", { className: "Icon-shape", x: "22", y: "11", width: "21", height: "78" })
    )
  );
};

/**
 * Previous
 */
var PreviousIcon = exports.PreviousIcon = function PreviousIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon PreviousIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement("polygon", { className: "Icon-shape", points: "85 12.6092632 27.3529412 44.5358947 27.3529412 11 15 11 15 89 27.3529412 89 27.3529412 54.368 85 86.3028421" })
  );
};

/**
 * Next
 */
var NextIcon = exports.NextIcon = function NextIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon NextIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement("polygon", { className: "Icon-shape", points: "72.6470588 11 72.6470588 44.1141176 15 12.0911765 15 85.9988235 72.6470588 53.9717647 72.6470588 89.2352941 85 89.2352941 85 11" })
  );
};

/**
 * Sound on
 */
var SoundOnIcon = exports.SoundOnIcon = function SoundOnIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon SoundOnIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement(
      "g",
      { className: "Icon-shape" },
      _react2.default.createElement("path", { d: "M28.0748663,36.3636364 L0,36.3636364 L0,65.9090909 L30.4812834,65.9090909 L54.5454545,88.6363636 L54.5454545,11.3636364 L28.0748663,36.3636364 Z" }),
      _react2.default.createElement("path", { d: "M84.6032335,82.4592965 C94.5340754,74.7600841 100.468182,62.9599381 100.468182,50.1791986 C100.468182,38.1777252 95.2347685,27.0146095 86.3177905,19.2913999 L80.3660059,26.1631456 C87.313543,32.1805749 91.3772727,40.8487007 91.3772727,50.1791986 C91.3772727,60.1143215 86.7696647,69.2766862 79.0331302,75.2746895 L84.6032335,82.4592965 L84.6032335,82.4592965 Z" }),
      _react2.default.createElement("path", { d: "M68.6941426,71.5946428 C75.48494,66.3298533 79.5454545,58.2554001 79.5454545,49.5119787 C79.5454545,41.3018627 75.9644339,33.663378 69.8670756,28.382309 L63.9152911,35.2540546 C68.0432084,38.8293434 70.4545455,43.9728382 70.4545455,49.5119787 C70.4545455,55.4097835 67.7205293,60.8464555 63.1240393,64.4100358 L68.6941426,71.5946428 L68.6941426,71.5946428 Z" })
    )
  );
};

var SoundOffIcon = exports.SoundOffIcon = function SoundOffIcon() {
  return _react2.default.createElement(
    "svg",
    { className: "Icon SoundOffIcon", viewBox: "0 0 100 100" },
    _react2.default.createElement(
      "g",
      { className: "Icon-shape" },
      _react2.default.createElement("path", { d: "M28.0748663,36.3636364 L0,36.3636364 L0,65.9090909 L30.4812834,65.9090909 L54.5454545,88.6363636 L54.5454545,11.3636364 L28.0748663,36.3636364 Z" }),
      _react2.default.createElement("polygon", { points: "69.513151 44.1232126 87.6949692 62.3050308 90.9090909 65.5191526 97.3373344 59.0909091 94.1232126 55.8767874 75.9413945 37.6949692 72.7272727 34.4808474 66.2990293 40.9090909" }),
      _react2.default.createElement("polygon", { points: "75.9413945 62.3050308 94.1232126 44.1232126 97.3373344 40.9090909 90.9090909 34.4808474 87.6949692 37.6949692 69.513151 55.8767874 66.2990293 59.0909091 72.7272727 65.5191526" })
    )
  );
};

/***/ }),
/* 87 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

/**
 * Base button component
 */
var Button = (_class = function (_Component) {
  _inherits(Button, _Component);

  function Button() {
    _classCallCheck(this, Button);

    return _possibleConstructorReturn(this, (Button.__proto__ || Object.getPrototypeOf(Button)).apply(this, arguments));
  }

  _createClass(Button, [{
    key: 'handleClick',
    value: function handleClick() {
      if (this.props.isEnabled) {
        this.props.onClick();
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _props = this.props,
          isEnabled = _props.isEnabled,
          className = _props.className,
          extraClasses = _props.extraClasses,
          style = _props.style,
          children = _props.children;


      return _react2.default.createElement(
        'button',
        {
          className: (0, _classnames2.default)(className, { isEnabled: isEnabled }, extraClasses),
          style: style,
          disabled: !isEnabled,
          onClick: this.handleClick
        },
        children
      );
    }
  }]);

  return Button;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'handleClick', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleClick'), _class.prototype)), _class);
Button.propTypes = {
  onClick: _propTypes2.default.func.isRequired,
  isEnabled: _propTypes2.default.bool,
  className: _propTypes2.default.string,
  extraClasses: _propTypes2.default.string,
  style: _propTypes2.default.object,
  children: _propTypes2.default.node
};
Button.defaultProps = {
  isEnabled: true,
  className: 'Button',
  extraClasses: '',
  style: {},
  children: null
};
exports.default = Button;

/***/ }),
/* 88 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.withChildClasses = exports.withCustomizableClasses = exports.withChildrenStyles = exports.compose = 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 _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _lodash = __webpack_require__(238);

var _lodash2 = _interopRequireDefault(_lodash);

var _lodash3 = __webpack_require__(239);

var _lodash4 = _interopRequireDefault(_lodash3);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * For clarification
 */
var compose = exports.compose = _lodash4.default;

/**
 * Adds `childrenStyles` prop type and default prop to
 * a component
 */
var withChildrenStyles = exports.withChildrenStyles = (0, _lodash2.default)(function (Component) {
  Component.propTypes = _extends({}, Component.propTypes || {}, {
    childrenStyles: _propTypes2.default.object
  });

  Component.defaultProps = _extends({}, Component.defaultProps || {}, {
    childrenStyles: {}
  });

  return Component;
});

/**
 *
 */
var withCustomizableClasses = exports.withCustomizableClasses = (0, _lodash2.default)(function (defaultClassName, Component) {
  Component.propTypes = _extends({}, Component.propTypes || {}, {
    className: _propTypes2.default.string,
    extraClasses: _propTypes2.default.string
  });

  Component.defaultProps = _extends({}, Component.defaultProps || {}, {
    className: defaultClassName,
    extraClasses: ''
  });

  return Component;
});

/**
 * Adds a `childClasses` prop type definition together with an empty
 * defaults object to a provided component.
 */
var withChildClasses = exports.withChildClasses = (0, _lodash2.default)(function (Component) {
  Component.propTypes = _extends({}, Component.propTypes || {}, {
    childClasses: _propTypes2.default.object
  });

  Component.defaultProps = _extends({}, Component.defaultProps || {}, {
    childClasses: {}
  });

  return Component;
});

/***/ }),
/* 89 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * @copyright 2015, Andrey Popp <8mayday@gmail.com>
 *
 * The decorator may be used on classes or methods
 * ```
 * @autobind
 * class FullBound {}
 *
 * class PartBound {
 *   @autobind
 *   method () {}
 * }
 * ```
 */


Object.defineProperty(exports, '__esModule', {
  value: true
});
exports['default'] = autobind;

function autobind() {
  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  if (args.length === 1) {
    return boundClass.apply(undefined, args);
  } else {
    return boundMethod.apply(undefined, args);
  }
}

/**
 * Use boundMethod to bind all methods on the target.prototype
 */
function boundClass(target) {
  // (Using reflect to get all keys including symbols)
  var keys = undefined;
  // Use Reflect if exists
  if (typeof Reflect !== 'undefined' && typeof Reflect.ownKeys === 'function') {
    keys = Reflect.ownKeys(target.prototype);
  } else {
    keys = Object.getOwnPropertyNames(target.prototype);
    // use symbols if support is provided
    if (typeof Object.getOwnPropertySymbols === 'function') {
      keys = keys.concat(Object.getOwnPropertySymbols(target.prototype));
    }
  }

  keys.forEach(function (key) {
    // Ignore special case target method
    if (key === 'constructor') {
      return;
    }

    var descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);

    // Only methods need binding
    if (typeof descriptor.value === 'function') {
      Object.defineProperty(target.prototype, key, boundMethod(target, key, descriptor));
    }
  });
  return target;
}

/**
 * Return a descriptor removing the value and returning a getter
 * The getter will return a .bind version of the function
 * and memoize the result against a symbol on the instance
 */
function boundMethod(target, key, descriptor) {
  var fn = descriptor.value;

  if (typeof fn !== 'function') {
    throw new Error('@autobind decorator can only be applied to methods not: ' + typeof fn);
  }

  // In IE11 calling Object.defineProperty has a side-effect of evaluating the
  // getter for the property which is being replaced. This causes infinite
  // recursion and an "Out of stack space" error.
  var definingProperty = false;

  return {
    configurable: true,
    get: function get() {
      if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
        return fn;
      }

      var boundFn = fn.bind(this);
      definingProperty = true;
      Object.defineProperty(this, key, {
        value: boundFn,
        configurable: true,
        writable: true
      });
      definingProperty = false;
      return boundFn;
    }
  };
}
module.exports = exports['default'];


/***/ }),
/* 90 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var PooledClass = __webpack_require__(91);
var ReactElement = __webpack_require__(14);

var emptyFunction = __webpack_require__(8);
var traverseAllChildren = __webpack_require__(92);

var twoArgumentPooler = PooledClass.twoArgumentPooler;
var fourArgumentPooler = PooledClass.fourArgumentPooler;

var userProvidedKeyEscapeRegex = /\/+/g;
function escapeUserProvidedKey(text) {
  return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
}

/**
 * PooledClass representing the bookkeeping associated with performing a child
 * traversal. Allows avoiding binding callbacks.
 *
 * @constructor ForEachBookKeeping
 * @param {!function} forEachFunction Function to perform traversal with.
 * @param {?*} forEachContext Context to perform context with.
 */
function ForEachBookKeeping(forEachFunction, forEachContext) {
  this.func = forEachFunction;
  this.context = forEachContext;
  this.count = 0;
}
ForEachBookKeeping.prototype.destructor = function () {
  this.func = null;
  this.context = null;
  this.count = 0;
};
PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);

function forEachSingleChild(bookKeeping, child, name) {
  var func = bookKeeping.func,
      context = bookKeeping.context;

  func.call(context, child, bookKeeping.count++);
}

/**
 * Iterates through children that are typically specified as `props.children`.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#react.children.foreach
 *
 * The provided forEachFunc(child, index) will be called for each
 * leaf child.
 *
 * @param {?*} children Children tree container.
 * @param {function(*, int)} forEachFunc
 * @param {*} forEachContext Context for forEachContext.
 */
function forEachChildren(children, forEachFunc, forEachContext) {
  if (children == null) {
    return children;
  }
  var traverseContext = ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
  traverseAllChildren(children, forEachSingleChild, traverseContext);
  ForEachBookKeeping.release(traverseContext);
}

/**
 * PooledClass representing the bookkeeping associated with performing a child
 * mapping. Allows avoiding binding callbacks.
 *
 * @constructor MapBookKeeping
 * @param {!*} mapResult Object containing the ordered map of results.
 * @param {!function} mapFunction Function to perform mapping with.
 * @param {?*} mapContext Context to perform mapping with.
 */
function MapBookKeeping(mapResult, keyPrefix, mapFunction, mapContext) {
  this.result = mapResult;
  this.keyPrefix = keyPrefix;
  this.func = mapFunction;
  this.context = mapContext;
  this.count = 0;
}
MapBookKeeping.prototype.destructor = function () {
  this.result = null;
  this.keyPrefix = null;
  this.func = null;
  this.context = null;
  this.count = 0;
};
PooledClass.addPoolingTo(MapBookKeeping, fourArgumentPooler);

function mapSingleChildIntoContext(bookKeeping, child, childKey) {
  var result = bookKeeping.result,
      keyPrefix = bookKeeping.keyPrefix,
      func = bookKeeping.func,
      context = bookKeeping.context;


  var mappedChild = func.call(context, child, bookKeeping.count++);
  if (Array.isArray(mappedChild)) {
    mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, emptyFunction.thatReturnsArgument);
  } else if (mappedChild != null) {
    if (ReactElement.isValidElement(mappedChild)) {
      mappedChild = ReactElement.cloneAndReplaceKey(mappedChild,
      // Keep both the (mapped) and old keys if they differ, just as
      // traverseAllChildren used to do for objects as children
      keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey);
    }
    result.push(mappedChild);
  }
}

function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
  var escapedPrefix = '';
  if (prefix != null) {
    escapedPrefix = escapeUserProvidedKey(prefix) + '/';
  }
  var traverseContext = MapBookKeeping.getPooled(array, escapedPrefix, func, context);
  traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
  MapBookKeeping.release(traverseContext);
}

/**
 * Maps children that are typically specified as `props.children`.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#react.children.map
 *
 * The provided mapFunction(child, key, index) will be called for each
 * leaf child.
 *
 * @param {?*} children Children tree container.
 * @param {function(*, int)} func The map function.
 * @param {*} context Context for mapFunction.
 * @return {object} Object containing the ordered map of results.
 */
function mapChildren(children, func, context) {
  if (children == null) {
    return children;
  }
  var result = [];
  mapIntoWithKeyPrefixInternal(children, result, null, func, context);
  return result;
}

function forEachSingleChildDummy(traverseContext, child, name) {
  return null;
}

/**
 * Count the number of children that are typically specified as
 * `props.children`.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#react.children.count
 *
 * @param {?*} children Children tree container.
 * @return {number} The number of children.
 */
function countChildren(children, context) {
  return traverseAllChildren(children, forEachSingleChildDummy, null);
}

/**
 * Flatten a children object (typically specified as `props.children`) and
 * return an array with appropriately re-keyed children.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#react.children.toarray
 */
function toArray(children) {
  var result = [];
  mapIntoWithKeyPrefixInternal(children, result, null, emptyFunction.thatReturnsArgument);
  return result;
}

var ReactChildren = {
  forEach: forEachChildren,
  map: mapChildren,
  mapIntoWithKeyPrefixInternal: mapIntoWithKeyPrefixInternal,
  count: countChildren,
  toArray: toArray
};

module.exports = ReactChildren;

/***/ }),
/* 91 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(17);

var invariant = __webpack_require__(0);

/**
 * Static poolers. Several custom versions for each potential number of
 * arguments. A completely generic pooler is easy to implement, but would
 * require accessing the `arguments` object. In each of these, `this` refers to
 * the Class itself, not an instance. If any others are needed, simply add them
 * here, or in their own files.
 */
var oneArgumentPooler = function (copyFieldsFrom) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, copyFieldsFrom);
    return instance;
  } else {
    return new Klass(copyFieldsFrom);
  }
};

var twoArgumentPooler = function (a1, a2) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2);
    return instance;
  } else {
    return new Klass(a1, a2);
  }
};

var threeArgumentPooler = function (a1, a2, a3) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3);
    return instance;
  } else {
    return new Klass(a1, a2, a3);
  }
};

var fourArgumentPooler = function (a1, a2, a3, a4) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3, a4);
    return instance;
  } else {
    return new Klass(a1, a2, a3, a4);
  }
};

var standardReleaser = function (instance) {
  var Klass = this;
  !(instance instanceof Klass) ?  true ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
  instance.destructor();
  if (Klass.instancePool.length < Klass.poolSize) {
    Klass.instancePool.push(instance);
  }
};

var DEFAULT_POOL_SIZE = 10;
var DEFAULT_POOLER = oneArgumentPooler;

/**
 * Augments `CopyConstructor` to be a poolable class, augmenting only the class
 * itself (statically) not adding any prototypical fields. Any CopyConstructor
 * you give this may have a `poolSize` property, and will look for a
 * prototypical `destructor` on instances.
 *
 * @param {Function} CopyConstructor Constructor that can be used to reset.
 * @param {Function} pooler Customizable pooler.
 */
var addPoolingTo = function (CopyConstructor, pooler) {
  // Casting as any so that flow ignores the actual implementation and trusts
  // it to match the type we declared
  var NewKlass = CopyConstructor;
  NewKlass.instancePool = [];
  NewKlass.getPooled = pooler || DEFAULT_POOLER;
  if (!NewKlass.poolSize) {
    NewKlass.poolSize = DEFAULT_POOL_SIZE;
  }
  NewKlass.release = standardReleaser;
  return NewKlass;
};

var PooledClass = {
  addPoolingTo: addPoolingTo,
  oneArgumentPooler: oneArgumentPooler,
  twoArgumentPooler: twoArgumentPooler,
  threeArgumentPooler: threeArgumentPooler,
  fourArgumentPooler: fourArgumentPooler
};

module.exports = PooledClass;

/***/ }),
/* 92 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(17);

var ReactCurrentOwner = __webpack_require__(9);
var REACT_ELEMENT_TYPE = __webpack_require__(54);

var getIteratorFn = __webpack_require__(55);
var invariant = __webpack_require__(0);
var KeyEscapeUtils = __webpack_require__(93);
var warning = __webpack_require__(1);

var SEPARATOR = '.';
var SUBSEPARATOR = ':';

/**
 * This is inlined from ReactElement since this file is shared between
 * isomorphic and renderers. We could extract this to a
 *
 */

/**
 * TODO: Test that a single child and an array with one item have the same key
 * pattern.
 */

var didWarnAboutMaps = false;

/**
 * Generate a key string that identifies a component within a set.
 *
 * @param {*} component A component that could contain a manual key.
 * @param {number} index Index that is used if a manual key is not provided.
 * @return {string}
 */
function getComponentKey(component, index) {
  // Do some typechecking here since we call this blindly. We want to ensure
  // that we don't block potential future ES APIs.
  if (component && typeof component === 'object' && component.key != null) {
    // Explicit key
    return KeyEscapeUtils.escape(component.key);
  }
  // Implicit key determined by the index in the set
  return index.toString(36);
}

/**
 * @param {?*} children Children tree container.
 * @param {!string} nameSoFar Name of the key path so far.
 * @param {!function} callback Callback to invoke with each child found.
 * @param {?*} traverseContext Used to pass information throughout the traversal
 * process.
 * @return {!number} The number of children in this subtree.
 */
function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
  var type = typeof children;

  if (type === 'undefined' || type === 'boolean') {
    // All of the above are perceived as null.
    children = null;
  }

  if (children === null || type === 'string' || type === 'number' ||
  // The following is inlined from ReactElement. This means we can optimize
  // some checks. React Fiber also inlines this logic for similar purposes.
  type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) {
    callback(traverseContext, children,
    // If it's the only child, treat the name as if it was wrapped in an array
    // so that it's consistent if the number of children grows.
    nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
    return 1;
  }

  var child;
  var nextName;
  var subtreeCount = 0; // Count of children found in the current subtree.
  var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;

  if (Array.isArray(children)) {
    for (var i = 0; i < children.length; i++) {
      child = children[i];
      nextName = nextNamePrefix + getComponentKey(child, i);
      subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
    }
  } else {
    var iteratorFn = getIteratorFn(children);
    if (iteratorFn) {
      var iterator = iteratorFn.call(children);
      var step;
      if (iteratorFn !== children.entries) {
        var ii = 0;
        while (!(step = iterator.next()).done) {
          child = step.value;
          nextName = nextNamePrefix + getComponentKey(child, ii++);
          subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
        }
      } else {
        if (true) {
          var mapsAsChildrenAddendum = '';
          if (ReactCurrentOwner.current) {
            var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
            if (mapsAsChildrenOwnerName) {
              mapsAsChildrenAddendum = ' Check the render method of `' + mapsAsChildrenOwnerName + '`.';
            }
          }
           true ? warning(didWarnAboutMaps, 'Using Maps as children is not yet fully supported. It is an ' + 'experimental feature that might be removed. Convert it to a ' + 'sequence / iterable of keyed ReactElements instead.%s', mapsAsChildrenAddendum) : void 0;
          didWarnAboutMaps = true;
        }
        // Iterator will provide entry [k,v] tuples rather than values.
        while (!(step = iterator.next()).done) {
          var entry = step.value;
          if (entry) {
            child = entry[1];
            nextName = nextNamePrefix + KeyEscapeUtils.escape(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
            subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
          }
        }
      }
    } else if (type === 'object') {
      var addendum = '';
      if (true) {
        addendum = ' If you meant to render a collection of children, use an array ' + 'instead or wrap the object using createFragment(object) from the ' + 'React add-ons.';
        if (children._isReactElement) {
          addendum = " It looks like you're using an element created by a different " + 'version of React. Make sure to use only one copy of React.';
        }
        if (ReactCurrentOwner.current) {
          var name = ReactCurrentOwner.current.getName();
          if (name) {
            addendum += ' Check the render method of `' + name + '`.';
          }
        }
      }
      var childrenString = String(children);
       true ?  true ? invariant(false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : _prodInvariant('31', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum) : void 0;
    }
  }

  return subtreeCount;
}

/**
 * Traverses children that are typically specified as `props.children`, but
 * might also be specified through attributes:
 *
 * - `traverseAllChildren(this.props.children, ...)`
 * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
 *
 * The `traverseContext` is an optional argument that is passed through the
 * entire traversal. It can be used to store accumulations or anything else that
 * the callback might find relevant.
 *
 * @param {?*} children Children tree object.
 * @param {!function} callback To invoke upon traversing each child.
 * @param {?*} traverseContext Context for traversal.
 * @return {!number} The number of children in this subtree.
 */
function traverseAllChildren(children, callback, traverseContext) {
  if (children == null) {
    return 0;
  }

  return traverseAllChildrenImpl(children, '', callback, traverseContext);
}

module.exports = traverseAllChildren;

/***/ }),
/* 93 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/**
 * Escape and wrap key so it is safe to use as a reactid
 *
 * @param {string} key to be escaped.
 * @return {string} the escaped key.
 */

function escape(key) {
  var escapeRegex = /[=:]/g;
  var escaperLookup = {
    '=': '=0',
    ':': '=2'
  };
  var escapedString = ('' + key).replace(escapeRegex, function (match) {
    return escaperLookup[match];
  });

  return '$' + escapedString;
}

/**
 * Unescape and unwrap key for human-readable display
 *
 * @param {string} key to unescape.
 * @return {string} the unescaped key.
 */
function unescape(key) {
  var unescapeRegex = /(=0|=2)/g;
  var unescaperLookup = {
    '=0': '=',
    '=2': ':'
  };
  var keySubstring = key[0] === '.' && key[1] === '$' ? key.substring(2) : key.substring(1);

  return ('' + keySubstring).replace(unescapeRegex, function (match) {
    return unescaperLookup[match];
  });
}

var KeyEscapeUtils = {
  escape: escape,
  unescape: unescape
};

module.exports = KeyEscapeUtils;

/***/ }),
/* 94 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactElement = __webpack_require__(14);

/**
 * Create a factory that creates HTML tag elements.
 *
 * @private
 */
var createDOMFactory = ReactElement.createFactory;
if (true) {
  var ReactElementValidator = __webpack_require__(56);
  createDOMFactory = ReactElementValidator.createFactory;
}

/**
 * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
 *
 * @public
 */
var ReactDOMFactories = {
  a: createDOMFactory('a'),
  abbr: createDOMFactory('abbr'),
  address: createDOMFactory('address'),
  area: createDOMFactory('area'),
  article: createDOMFactory('article'),
  aside: createDOMFactory('aside'),
  audio: createDOMFactory('audio'),
  b: createDOMFactory('b'),
  base: createDOMFactory('base'),
  bdi: createDOMFactory('bdi'),
  bdo: createDOMFactory('bdo'),
  big: createDOMFactory('big'),
  blockquote: createDOMFactory('blockquote'),
  body: createDOMFactory('body'),
  br: createDOMFactory('br'),
  button: createDOMFactory('button'),
  canvas: createDOMFactory('canvas'),
  caption: createDOMFactory('caption'),
  cite: createDOMFactory('cite'),
  code: createDOMFactory('code'),
  col: createDOMFactory('col'),
  colgroup: createDOMFactory('colgroup'),
  data: createDOMFactory('data'),
  datalist: createDOMFactory('datalist'),
  dd: createDOMFactory('dd'),
  del: createDOMFactory('del'),
  details: createDOMFactory('details'),
  dfn: createDOMFactory('dfn'),
  dialog: createDOMFactory('dialog'),
  div: createDOMFactory('div'),
  dl: createDOMFactory('dl'),
  dt: createDOMFactory('dt'),
  em: createDOMFactory('em'),
  embed: createDOMFactory('embed'),
  fieldset: createDOMFactory('fieldset'),
  figcaption: createDOMFactory('figcaption'),
  figure: createDOMFactory('figure'),
  footer: createDOMFactory('footer'),
  form: createDOMFactory('form'),
  h1: createDOMFactory('h1'),
  h2: createDOMFactory('h2'),
  h3: createDOMFactory('h3'),
  h4: createDOMFactory('h4'),
  h5: createDOMFactory('h5'),
  h6: createDOMFactory('h6'),
  head: createDOMFactory('head'),
  header: createDOMFactory('header'),
  hgroup: createDOMFactory('hgroup'),
  hr: createDOMFactory('hr'),
  html: createDOMFactory('html'),
  i: createDOMFactory('i'),
  iframe: createDOMFactory('iframe'),
  img: createDOMFactory('img'),
  input: createDOMFactory('input'),
  ins: createDOMFactory('ins'),
  kbd: createDOMFactory('kbd'),
  keygen: createDOMFactory('keygen'),
  label: createDOMFactory('label'),
  legend: createDOMFactory('legend'),
  li: createDOMFactory('li'),
  link: createDOMFactory('link'),
  main: createDOMFactory('main'),
  map: createDOMFactory('map'),
  mark: createDOMFactory('mark'),
  menu: createDOMFactory('menu'),
  menuitem: createDOMFactory('menuitem'),
  meta: createDOMFactory('meta'),
  meter: createDOMFactory('meter'),
  nav: createDOMFactory('nav'),
  noscript: createDOMFactory('noscript'),
  object: createDOMFactory('object'),
  ol: createDOMFactory('ol'),
  optgroup: createDOMFactory('optgroup'),
  option: createDOMFactory('option'),
  output: createDOMFactory('output'),
  p: createDOMFactory('p'),
  param: createDOMFactory('param'),
  picture: createDOMFactory('picture'),
  pre: createDOMFactory('pre'),
  progress: createDOMFactory('progress'),
  q: createDOMFactory('q'),
  rp: createDOMFactory('rp'),
  rt: createDOMFactory('rt'),
  ruby: createDOMFactory('ruby'),
  s: createDOMFactory('s'),
  samp: createDOMFactory('samp'),
  script: createDOMFactory('script'),
  section: createDOMFactory('section'),
  select: createDOMFactory('select'),
  small: createDOMFactory('small'),
  source: createDOMFactory('source'),
  span: createDOMFactory('span'),
  strong: createDOMFactory('strong'),
  style: createDOMFactory('style'),
  sub: createDOMFactory('sub'),
  summary: createDOMFactory('summary'),
  sup: createDOMFactory('sup'),
  table: createDOMFactory('table'),
  tbody: createDOMFactory('tbody'),
  td: createDOMFactory('td'),
  textarea: createDOMFactory('textarea'),
  tfoot: createDOMFactory('tfoot'),
  th: createDOMFactory('th'),
  thead: createDOMFactory('thead'),
  time: createDOMFactory('time'),
  title: createDOMFactory('title'),
  tr: createDOMFactory('tr'),
  track: createDOMFactory('track'),
  u: createDOMFactory('u'),
  ul: createDOMFactory('ul'),
  'var': createDOMFactory('var'),
  video: createDOMFactory('video'),
  wbr: createDOMFactory('wbr'),

  // SVG
  circle: createDOMFactory('circle'),
  clipPath: createDOMFactory('clipPath'),
  defs: createDOMFactory('defs'),
  ellipse: createDOMFactory('ellipse'),
  g: createDOMFactory('g'),
  image: createDOMFactory('image'),
  line: createDOMFactory('line'),
  linearGradient: createDOMFactory('linearGradient'),
  mask: createDOMFactory('mask'),
  path: createDOMFactory('path'),
  pattern: createDOMFactory('pattern'),
  polygon: createDOMFactory('polygon'),
  polyline: createDOMFactory('polyline'),
  radialGradient: createDOMFactory('radialGradient'),
  rect: createDOMFactory('rect'),
  stop: createDOMFactory('stop'),
  svg: createDOMFactory('svg'),
  text: createDOMFactory('text'),
  tspan: createDOMFactory('tspan')
};

module.exports = ReactDOMFactories;

/***/ }),
/* 95 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(process) {/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(17);

var ReactPropTypeLocationNames = __webpack_require__(96);
var ReactPropTypesSecret = __webpack_require__(97);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

var ReactComponentTreeHook;

if (typeof process !== 'undefined' && process.env && "test" === 'test') {
  // Temporary hack.
  // Inline requires don't work well with Jest:
  // https://github.com/facebook/react/issues/7240
  // Remove the inline requires when we don't need them anymore:
  // https://github.com/facebook/react/pull/7178
  ReactComponentTreeHook = __webpack_require__(6);
}

var loggedTypeFailures = {};

/**
 * Assert that the values match with the type specs.
 * Error messages are memorized and will only be shown once.
 *
 * @param {object} typeSpecs Map of name to a ReactPropType
 * @param {object} values Runtime values that need to be type-checked
 * @param {string} location e.g. "prop", "context", "child context"
 * @param {string} componentName Name of the component for error messages.
 * @param {?object} element The React element that is being type-checked
 * @param {?number} debugID The React component instance that is being type-checked
 * @private
 */
function checkReactTypeSpec(typeSpecs, values, location, componentName, element, debugID) {
  for (var typeSpecName in typeSpecs) {
    if (typeSpecs.hasOwnProperty(typeSpecName)) {
      var error;
      // Prop type validation may throw. In case they do, we don't want to
      // fail the render phase where it didn't fail before. So we log it.
      // After these have been cleaned up, we'll let them throw.
      try {
        // This is intentionally an invariant that gets caught. It's the same
        // behavior as without this statement except with a better message.
        !(typeof typeSpecs[typeSpecName] === 'function') ?  true ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : _prodInvariant('84', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : void 0;
        error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
      } catch (ex) {
        error = ex;
      }
       true ? warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName, typeof error) : void 0;
      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
        // Only monitor this failure once because there tends to be a lot of the
        // same error.
        loggedTypeFailures[error.message] = true;

        var componentStackInfo = '';

        if (true) {
          if (!ReactComponentTreeHook) {
            ReactComponentTreeHook = __webpack_require__(6);
          }
          if (debugID !== null) {
            componentStackInfo = ReactComponentTreeHook.getStackAddendumByID(debugID);
          } else if (element !== null) {
            componentStackInfo = ReactComponentTreeHook.getCurrentStackAddendum(element);
          }
        }

         true ? warning(false, 'Failed %s type: %s%s', location, error.message, componentStackInfo) : void 0;
      }
    }
  }
}

module.exports = checkReactTypeSpec;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)))

/***/ }),
/* 96 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactPropTypeLocationNames = {};

if (true) {
  ReactPropTypeLocationNames = {
    prop: 'prop',
    context: 'context',
    childContext: 'child context'
  };
}

module.exports = ReactPropTypeLocationNames;

/***/ }),
/* 97 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';

module.exports = ReactPropTypesSecret;

/***/ }),
/* 98 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _require = __webpack_require__(14),
    isValidElement = _require.isValidElement;

var factory = __webpack_require__(57);

module.exports = factory(isValidElement);

/***/ }),
/* 99 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */



if (true) {
  var invariant = __webpack_require__(0);
  var warning = __webpack_require__(1);
  var ReactPropTypesSecret = __webpack_require__(58);
  var loggedTypeFailures = {};
}

/**
 * Assert that the values match with the type specs.
 * Error messages are memorized and will only be shown once.
 *
 * @param {object} typeSpecs Map of name to a ReactPropType
 * @param {object} values Runtime values that need to be type-checked
 * @param {string} location e.g. "prop", "context", "child context"
 * @param {string} componentName Name of the component for error messages.
 * @param {?Function} getStack Returns the component stack.
 * @private
 */
function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
  if (true) {
    for (var typeSpecName in typeSpecs) {
      if (typeSpecs.hasOwnProperty(typeSpecName)) {
        var error;
        // Prop type validation may throw. In case they do, we don't want to
        // fail the render phase where it didn't fail before. So we log it.
        // After these have been cleaned up, we'll let them throw.
        try {
          // This is intentionally an invariant that gets caught. It's the same
          // behavior as without this statement except with a better message.
          invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]);
          error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
        } catch (ex) {
          error = ex;
        }
        warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error);
        if (error instanceof Error && !(error.message in loggedTypeFailures)) {
          // Only monitor this failure once because there tends to be a lot of the
          // same error.
          loggedTypeFailures[error.message] = true;

          var stack = getStack ? getStack() : '';

          warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
        }
      }
    }
  }
}

module.exports = checkPropTypes;


/***/ }),
/* 100 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



module.exports = '15.6.2';

/***/ }),
/* 101 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _require = __webpack_require__(52),
    Component = _require.Component;

var _require2 = __webpack_require__(14),
    isValidElement = _require2.isValidElement;

var ReactNoopUpdateQueue = __webpack_require__(53);
var factory = __webpack_require__(102);

module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue);

/***/ }),
/* 102 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var emptyObject = __webpack_require__(27);
var _invariant = __webpack_require__(0);

if (true) {
  var warning = __webpack_require__(1);
}

var MIXINS_KEY = 'mixins';

// Helper function to allow the creation of anonymous functions which do not
// have .name set to the name of the variable being assigned to.
function identity(fn) {
  return fn;
}

var ReactPropTypeLocationNames;
if (true) {
  ReactPropTypeLocationNames = {
    prop: 'prop',
    context: 'context',
    childContext: 'child context'
  };
} else {
  ReactPropTypeLocationNames = {};
}

function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
  /**
   * Policies that describe methods in `ReactClassInterface`.
   */

  var injectedMixins = [];

  /**
   * Composite components are higher-level components that compose other composite
   * or host components.
   *
   * To create a new type of `ReactClass`, pass a specification of
   * your new class to `React.createClass`. The only requirement of your class
   * specification is that you implement a `render` method.
   *
   *   var MyComponent = React.createClass({
   *     render: function() {
   *       return <div>Hello World</div>;
   *     }
   *   });
   *
   * The class specification supports a specific protocol of methods that have
   * special meaning (e.g. `render`). See `ReactClassInterface` for
   * more the comprehensive protocol. Any other properties and methods in the
   * class specification will be available on the prototype.
   *
   * @interface ReactClassInterface
   * @internal
   */
  var ReactClassInterface = {
    /**
     * An array of Mixin objects to include when defining your component.
     *
     * @type {array}
     * @optional
     */
    mixins: 'DEFINE_MANY',

    /**
     * An object containing properties and methods that should be defined on
     * the component's constructor instead of its prototype (static methods).
     *
     * @type {object}
     * @optional
     */
    statics: 'DEFINE_MANY',

    /**
     * Definition of prop types for this component.
     *
     * @type {object}
     * @optional
     */
    propTypes: 'DEFINE_MANY',

    /**
     * Definition of context types for this component.
     *
     * @type {object}
     * @optional
     */
    contextTypes: 'DEFINE_MANY',

    /**
     * Definition of context types this component sets for its children.
     *
     * @type {object}
     * @optional
     */
    childContextTypes: 'DEFINE_MANY',

    // ==== Definition methods ====

    /**
     * Invoked when the component is mounted. Values in the mapping will be set on
     * `this.props` if that prop is not specified (i.e. using an `in` check).
     *
     * This method is invoked before `getInitialState` and therefore cannot rely
     * on `this.state` or use `this.setState`.
     *
     * @return {object}
     * @optional
     */
    getDefaultProps: 'DEFINE_MANY_MERGED',

    /**
     * Invoked once before the component is mounted. The return value will be used
     * as the initial value of `this.state`.
     *
     *   getInitialState: function() {
     *     return {
     *       isOn: false,
     *       fooBaz: new BazFoo()
     *     }
     *   }
     *
     * @return {object}
     * @optional
     */
    getInitialState: 'DEFINE_MANY_MERGED',

    /**
     * @return {object}
     * @optional
     */
    getChildContext: 'DEFINE_MANY_MERGED',

    /**
     * Uses props from `this.props` and state from `this.state` to render the
     * structure of the component.
     *
     * No guarantees are made about when or how often this method is invoked, so
     * it must not have side effects.
     *
     *   render: function() {
     *     var name = this.props.name;
     *     return <div>Hello, {name}!</div>;
     *   }
     *
     * @return {ReactComponent}
     * @required
     */
    render: 'DEFINE_ONCE',

    // ==== Delegate methods ====

    /**
     * Invoked when the component is initially created and about to be mounted.
     * This may have side effects, but any external subscriptions or data created
     * by this method must be cleaned up in `componentWillUnmount`.
     *
     * @optional
     */
    componentWillMount: 'DEFINE_MANY',

    /**
     * Invoked when the component has been mounted and has a DOM representation.
     * However, there is no guarantee that the DOM node is in the document.
     *
     * Use this as an opportunity to operate on the DOM when the component has
     * been mounted (initialized and rendered) for the first time.
     *
     * @param {DOMElement} rootNode DOM element representing the component.
     * @optional
     */
    componentDidMount: 'DEFINE_MANY',

    /**
     * Invoked before the component receives new props.
     *
     * Use this as an opportunity to react to a prop transition by updating the
     * state using `this.setState`. Current props are accessed via `this.props`.
     *
     *   componentWillReceiveProps: function(nextProps, nextContext) {
     *     this.setState({
     *       likesIncreasing: nextProps.likeCount > this.props.likeCount
     *     });
     *   }
     *
     * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
     * transition may cause a state change, but the opposite is not true. If you
     * need it, you are probably looking for `componentWillUpdate`.
     *
     * @param {object} nextProps
     * @optional
     */
    componentWillReceiveProps: 'DEFINE_MANY',

    /**
     * Invoked while deciding if the component should be updated as a result of
     * receiving new props, state and/or context.
     *
     * Use this as an opportunity to `return false` when you're certain that the
     * transition to the new props/state/context will not require a component
     * update.
     *
     *   shouldComponentUpdate: function(nextProps, nextState, nextContext) {
     *     return !equal(nextProps, this.props) ||
     *       !equal(nextState, this.state) ||
     *       !equal(nextContext, this.context);
     *   }
     *
     * @param {object} nextProps
     * @param {?object} nextState
     * @param {?object} nextContext
     * @return {boolean} True if the component should update.
     * @optional
     */
    shouldComponentUpdate: 'DEFINE_ONCE',

    /**
     * Invoked when the component is about to update due to a transition from
     * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
     * and `nextContext`.
     *
     * Use this as an opportunity to perform preparation before an update occurs.
     *
     * NOTE: You **cannot** use `this.setState()` in this method.
     *
     * @param {object} nextProps
     * @param {?object} nextState
     * @param {?object} nextContext
     * @param {ReactReconcileTransaction} transaction
     * @optional
     */
    componentWillUpdate: 'DEFINE_MANY',

    /**
     * Invoked when the component's DOM representation has been updated.
     *
     * Use this as an opportunity to operate on the DOM when the component has
     * been updated.
     *
     * @param {object} prevProps
     * @param {?object} prevState
     * @param {?object} prevContext
     * @param {DOMElement} rootNode DOM element representing the component.
     * @optional
     */
    componentDidUpdate: 'DEFINE_MANY',

    /**
     * Invoked when the component is about to be removed from its parent and have
     * its DOM representation destroyed.
     *
     * Use this as an opportunity to deallocate any external resources.
     *
     * NOTE: There is no `componentDidUnmount` since your component will have been
     * destroyed by that point.
     *
     * @optional
     */
    componentWillUnmount: 'DEFINE_MANY',

    // ==== Advanced methods ====

    /**
     * Updates the component's currently mounted DOM representation.
     *
     * By default, this implements React's rendering and reconciliation algorithm.
     * Sophisticated clients may wish to override this.
     *
     * @param {ReactReconcileTransaction} transaction
     * @internal
     * @overridable
     */
    updateComponent: 'OVERRIDE_BASE'
  };

  /**
   * Mapping from class specification keys to special processing functions.
   *
   * Although these are declared like instance properties in the specification
   * when defining classes using `React.createClass`, they are actually static
   * and are accessible on the constructor instead of the prototype. Despite
   * being static, they must be defined outside of the "statics" key under
   * which all other static methods are defined.
   */
  var RESERVED_SPEC_KEYS = {
    displayName: function(Constructor, displayName) {
      Constructor.displayName = displayName;
    },
    mixins: function(Constructor, mixins) {
      if (mixins) {
        for (var i = 0; i < mixins.length; i++) {
          mixSpecIntoComponent(Constructor, mixins[i]);
        }
      }
    },
    childContextTypes: function(Constructor, childContextTypes) {
      if (true) {
        validateTypeDef(Constructor, childContextTypes, 'childContext');
      }
      Constructor.childContextTypes = _assign(
        {},
        Constructor.childContextTypes,
        childContextTypes
      );
    },
    contextTypes: function(Constructor, contextTypes) {
      if (true) {
        validateTypeDef(Constructor, contextTypes, 'context');
      }
      Constructor.contextTypes = _assign(
        {},
        Constructor.contextTypes,
        contextTypes
      );
    },
    /**
     * Special case getDefaultProps which should move into statics but requires
     * automatic merging.
     */
    getDefaultProps: function(Constructor, getDefaultProps) {
      if (Constructor.getDefaultProps) {
        Constructor.getDefaultProps = createMergedResultFunction(
          Constructor.getDefaultProps,
          getDefaultProps
        );
      } else {
        Constructor.getDefaultProps = getDefaultProps;
      }
    },
    propTypes: function(Constructor, propTypes) {
      if (true) {
        validateTypeDef(Constructor, propTypes, 'prop');
      }
      Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes);
    },
    statics: function(Constructor, statics) {
      mixStaticSpecIntoComponent(Constructor, statics);
    },
    autobind: function() {}
  };

  function validateTypeDef(Constructor, typeDef, location) {
    for (var propName in typeDef) {
      if (typeDef.hasOwnProperty(propName)) {
        // use a warning instead of an _invariant so components
        // don't show up in prod but only in __DEV__
        if (true) {
          warning(
            typeof typeDef[propName] === 'function',
            '%s: %s type `%s` is invalid; it must be a function, usually from ' +
              'React.PropTypes.',
            Constructor.displayName || 'ReactClass',
            ReactPropTypeLocationNames[location],
            propName
          );
        }
      }
    }
  }

  function validateMethodOverride(isAlreadyDefined, name) {
    var specPolicy = ReactClassInterface.hasOwnProperty(name)
      ? ReactClassInterface[name]
      : null;

    // Disallow overriding of base class methods unless explicitly allowed.
    if (ReactClassMixin.hasOwnProperty(name)) {
      _invariant(
        specPolicy === 'OVERRIDE_BASE',
        'ReactClassInterface: You are attempting to override ' +
          '`%s` from your class specification. Ensure that your method names ' +
          'do not overlap with React methods.',
        name
      );
    }

    // Disallow defining methods more than once unless explicitly allowed.
    if (isAlreadyDefined) {
      _invariant(
        specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED',
        'ReactClassInterface: You are attempting to define ' +
          '`%s` on your component more than once. This conflict may be due ' +
          'to a mixin.',
        name
      );
    }
  }

  /**
   * Mixin helper which handles policy validation and reserved
   * specification keys when building React classes.
   */
  function mixSpecIntoComponent(Constructor, spec) {
    if (!spec) {
      if (true) {
        var typeofSpec = typeof spec;
        var isMixinValid = typeofSpec === 'object' && spec !== null;

        if (true) {
          warning(
            isMixinValid,
            "%s: You're attempting to include a mixin that is either null " +
              'or not an object. Check the mixins included by the component, ' +
              'as well as any mixins they include themselves. ' +
              'Expected object but got %s.',
            Constructor.displayName || 'ReactClass',
            spec === null ? null : typeofSpec
          );
        }
      }

      return;
    }

    _invariant(
      typeof spec !== 'function',
      "ReactClass: You're attempting to " +
        'use a component class or function as a mixin. Instead, just use a ' +
        'regular object.'
    );
    _invariant(
      !isValidElement(spec),
      "ReactClass: You're attempting to " +
        'use a component as a mixin. Instead, just use a regular object.'
    );

    var proto = Constructor.prototype;
    var autoBindPairs = proto.__reactAutoBindPairs;

    // By handling mixins before any other properties, we ensure the same
    // chaining order is applied to methods with DEFINE_MANY policy, whether
    // mixins are listed before or after these methods in the spec.
    if (spec.hasOwnProperty(MIXINS_KEY)) {
      RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
    }

    for (var name in spec) {
      if (!spec.hasOwnProperty(name)) {
        continue;
      }

      if (name === MIXINS_KEY) {
        // We have already handled mixins in a special case above.
        continue;
      }

      var property = spec[name];
      var isAlreadyDefined = proto.hasOwnProperty(name);
      validateMethodOverride(isAlreadyDefined, name);

      if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
        RESERVED_SPEC_KEYS[name](Constructor, property);
      } else {
        // Setup methods on prototype:
        // The following member methods should not be automatically bound:
        // 1. Expected ReactClass methods (in the "interface").
        // 2. Overridden methods (that were mixed in).
        var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
        var isFunction = typeof property === 'function';
        var shouldAutoBind =
          isFunction &&
          !isReactClassMethod &&
          !isAlreadyDefined &&
          spec.autobind !== false;

        if (shouldAutoBind) {
          autoBindPairs.push(name, property);
          proto[name] = property;
        } else {
          if (isAlreadyDefined) {
            var specPolicy = ReactClassInterface[name];

            // These cases should already be caught by validateMethodOverride.
            _invariant(
              isReactClassMethod &&
                (specPolicy === 'DEFINE_MANY_MERGED' ||
                  specPolicy === 'DEFINE_MANY'),
              'ReactClass: Unexpected spec policy %s for key %s ' +
                'when mixing in component specs.',
              specPolicy,
              name
            );

            // For methods which are defined more than once, call the existing
            // methods before calling the new property, merging if appropriate.
            if (specPolicy === 'DEFINE_MANY_MERGED') {
              proto[name] = createMergedResultFunction(proto[name], property);
            } else if (specPolicy === 'DEFINE_MANY') {
              proto[name] = createChainedFunction(proto[name], property);
            }
          } else {
            proto[name] = property;
            if (true) {
              // Add verbose displayName to the function, which helps when looking
              // at profiling tools.
              if (typeof property === 'function' && spec.displayName) {
                proto[name].displayName = spec.displayName + '_' + name;
              }
            }
          }
        }
      }
    }
  }

  function mixStaticSpecIntoComponent(Constructor, statics) {
    if (!statics) {
      return;
    }
    for (var name in statics) {
      var property = statics[name];
      if (!statics.hasOwnProperty(name)) {
        continue;
      }

      var isReserved = name in RESERVED_SPEC_KEYS;
      _invariant(
        !isReserved,
        '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.',
        name
      );

      var isInherited = name in Constructor;
      _invariant(
        !isInherited,
        'ReactClass: You are attempting to define ' +
          '`%s` on your component more than once. This conflict may be ' +
          'due to a mixin.',
        name
      );
      Constructor[name] = property;
    }
  }

  /**
   * Merge two objects, but throw if both contain the same key.
   *
   * @param {object} one The first object, which is mutated.
   * @param {object} two The second object
   * @return {object} one after it has been mutated to contain everything in two.
   */
  function mergeIntoWithNoDuplicateKeys(one, two) {
    _invariant(
      one && two && typeof one === 'object' && typeof two === 'object',
      'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
    );

    for (var key in two) {
      if (two.hasOwnProperty(key)) {
        _invariant(
          one[key] === undefined,
          '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.',
          key
        );
        one[key] = two[key];
      }
    }
    return one;
  }

  /**
   * Creates a function that invokes two functions and merges their return values.
   *
   * @param {function} one Function to invoke first.
   * @param {function} two Function to invoke second.
   * @return {function} Function that invokes the two argument functions.
   * @private
   */
  function createMergedResultFunction(one, two) {
    return function mergedResult() {
      var a = one.apply(this, arguments);
      var b = two.apply(this, arguments);
      if (a == null) {
        return b;
      } else if (b == null) {
        return a;
      }
      var c = {};
      mergeIntoWithNoDuplicateKeys(c, a);
      mergeIntoWithNoDuplicateKeys(c, b);
      return c;
    };
  }

  /**
   * Creates a function that invokes two functions and ignores their return vales.
   *
   * @param {function} one Function to invoke first.
   * @param {function} two Function to invoke second.
   * @return {function} Function that invokes the two argument functions.
   * @private
   */
  function createChainedFunction(one, two) {
    return function chainedFunction() {
      one.apply(this, arguments);
      two.apply(this, arguments);
    };
  }

  /**
   * Binds a method to the component.
   *
   * @param {object} component Component whose method is going to be bound.
   * @param {function} method Method to be bound.
   * @return {function} The bound method.
   */
  function bindAutoBindMethod(component, method) {
    var boundMethod = method.bind(component);
    if (true) {
      boundMethod.__reactBoundContext = component;
      boundMethod.__reactBoundMethod = method;
      boundMethod.__reactBoundArguments = null;
      var componentName = component.constructor.displayName;
      var _bind = boundMethod.bind;
      boundMethod.bind = function(newThis) {
        for (
          var _len = arguments.length,
            args = Array(_len > 1 ? _len - 1 : 0),
            _key = 1;
          _key < _len;
          _key++
        ) {
          args[_key - 1] = arguments[_key];
        }

        // User is trying to bind() an autobound method; we effectively will
        // ignore the value of "this" that the user is trying to use, so
        // let's warn.
        if (newThis !== component && newThis !== null) {
          if (true) {
            warning(
              false,
              'bind(): React component methods may only be bound to the ' +
                'component instance. See %s',
              componentName
            );
          }
        } else if (!args.length) {
          if (true) {
            warning(
              false,
              'bind(): You are binding a component method to the component. ' +
                'React does this for you automatically in a high-performance ' +
                'way, so you can safely remove this call. See %s',
              componentName
            );
          }
          return boundMethod;
        }
        var reboundMethod = _bind.apply(boundMethod, arguments);
        reboundMethod.__reactBoundContext = component;
        reboundMethod.__reactBoundMethod = method;
        reboundMethod.__reactBoundArguments = args;
        return reboundMethod;
      };
    }
    return boundMethod;
  }

  /**
   * Binds all auto-bound methods in a component.
   *
   * @param {object} component Component whose method is going to be bound.
   */
  function bindAutoBindMethods(component) {
    var pairs = component.__reactAutoBindPairs;
    for (var i = 0; i < pairs.length; i += 2) {
      var autoBindKey = pairs[i];
      var method = pairs[i + 1];
      component[autoBindKey] = bindAutoBindMethod(component, method);
    }
  }

  var IsMountedPreMixin = {
    componentDidMount: function() {
      this.__isMounted = true;
    }
  };

  var IsMountedPostMixin = {
    componentWillUnmount: function() {
      this.__isMounted = false;
    }
  };

  /**
   * Add more to the ReactClass base class. These are all legacy features and
   * therefore not already part of the modern ReactComponent.
   */
  var ReactClassMixin = {
    /**
     * TODO: This will be deprecated because state should always keep a consistent
     * type signature and the only use case for this, is to avoid that.
     */
    replaceState: function(newState, callback) {
      this.updater.enqueueReplaceState(this, newState, callback);
    },

    /**
     * Checks whether or not this composite component is mounted.
     * @return {boolean} True if mounted, false otherwise.
     * @protected
     * @final
     */
    isMounted: function() {
      if (true) {
        warning(
          this.__didWarnIsMounted,
          '%s: isMounted is deprecated. Instead, make sure to clean up ' +
            'subscriptions and pending requests in componentWillUnmount to ' +
            'prevent memory leaks.',
          (this.constructor && this.constructor.displayName) ||
            this.name ||
            'Component'
        );
        this.__didWarnIsMounted = true;
      }
      return !!this.__isMounted;
    }
  };

  var ReactClassComponent = function() {};
  _assign(
    ReactClassComponent.prototype,
    ReactComponent.prototype,
    ReactClassMixin
  );

  /**
   * Creates a composite component class given a class specification.
   * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
   *
   * @param {object} spec Class specification (which must define `render`).
   * @return {function} Component constructor function.
   * @public
   */
  function createClass(spec) {
    // To keep our warnings more understandable, we'll use a little hack here to
    // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
    // unnecessarily identify a class without displayName as 'Constructor'.
    var Constructor = identity(function(props, context, updater) {
      // This constructor gets overridden by mocks. The argument is used
      // by mocks to assert on what gets mounted.

      if (true) {
        warning(
          this instanceof Constructor,
          'Something is calling a React component directly. Use a factory or ' +
            'JSX instead. See: https://fb.me/react-legacyfactory'
        );
      }

      // Wire up auto-binding
      if (this.__reactAutoBindPairs.length) {
        bindAutoBindMethods(this);
      }

      this.props = props;
      this.context = context;
      this.refs = emptyObject;
      this.updater = updater || ReactNoopUpdateQueue;

      this.state = null;

      // ReactClasses doesn't have constructors. Instead, they use the
      // getInitialState and componentWillMount methods for initialization.

      var initialState = this.getInitialState ? this.getInitialState() : null;
      if (true) {
        // We allow auto-mocks to proceed as if they're returning null.
        if (
          initialState === undefined &&
          this.getInitialState._isMockFunction
        ) {
          // This is probably bad practice. Consider warning here and
          // deprecating this convenience.
          initialState = null;
        }
      }
      _invariant(
        typeof initialState === 'object' && !Array.isArray(initialState),
        '%s.getInitialState(): must return an object or null',
        Constructor.displayName || 'ReactCompositeComponent'
      );

      this.state = initialState;
    });
    Constructor.prototype = new ReactClassComponent();
    Constructor.prototype.constructor = Constructor;
    Constructor.prototype.__reactAutoBindPairs = [];

    injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));

    mixSpecIntoComponent(Constructor, IsMountedPreMixin);
    mixSpecIntoComponent(Constructor, spec);
    mixSpecIntoComponent(Constructor, IsMountedPostMixin);

    // Initialize the defaultProps property after all mixins have been merged.
    if (Constructor.getDefaultProps) {
      Constructor.defaultProps = Constructor.getDefaultProps();
    }

    if (true) {
      // This is a tag to indicate that the use of these method names is ok,
      // since it's used with createClass. If it's not, then it's likely a
      // mistake so we'll warn you to use the static property, property
      // initializer or constructor respectively.
      if (Constructor.getDefaultProps) {
        Constructor.getDefaultProps.isReactClassApproved = {};
      }
      if (Constructor.prototype.getInitialState) {
        Constructor.prototype.getInitialState.isReactClassApproved = {};
      }
    }

    _invariant(
      Constructor.prototype.render,
      'createClass(...): Class specification must implement a `render` method.'
    );

    if (true) {
      warning(
        !Constructor.prototype.componentShouldUpdate,
        '%s has a method called ' +
          'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
          'The name is phrased as a question because the function is ' +
          'expected to return a value.',
        spec.displayName || 'A component'
      );
      warning(
        !Constructor.prototype.componentWillRecieveProps,
        '%s has a method called ' +
          'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
        spec.displayName || 'A component'
      );
    }

    // Reduce time spent doing lookups by setting these on the prototype.
    for (var methodName in ReactClassInterface) {
      if (!Constructor.prototype[methodName]) {
        Constructor.prototype[methodName] = null;
      }
    }

    return Constructor;
  }

  return createClass;
}

module.exports = factory;


/***/ }),
/* 103 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */


var _prodInvariant = __webpack_require__(17);

var ReactElement = __webpack_require__(14);

var invariant = __webpack_require__(0);

/**
 * Returns the first child in a collection of children and verifies that there
 * is only one child in the collection.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#react.children.only
 *
 * The current implementation of this function assumes that a single child gets
 * passed without a wrapper, but the purpose of this helper function is to
 * abstract away the particular structure of children.
 *
 * @param {?object} children Child collection structure.
 * @return {ReactElement} The first and only `ReactElement` contained in the
 * structure.
 */
function onlyChild(children) {
  !ReactElement.isValidElement(children) ?  true ? invariant(false, 'React.Children.only expected to receive a single React element child.') : _prodInvariant('143') : void 0;
  return children;
}

module.exports = onlyChild;

/***/ }),
/* 104 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


module.exports = __webpack_require__(105);


/***/ }),
/* 105 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/



var ReactDOMComponentTree = __webpack_require__(4);
var ReactDefaultInjection = __webpack_require__(106);
var ReactMount = __webpack_require__(82);
var ReactReconciler = __webpack_require__(18);
var ReactUpdates = __webpack_require__(10);
var ReactVersion = __webpack_require__(184);

var findDOMNode = __webpack_require__(185);
var getHostComponentFromComposite = __webpack_require__(83);
var renderSubtreeIntoContainer = __webpack_require__(186);
var warning = __webpack_require__(1);

ReactDefaultInjection.inject();

var ReactDOM = {
  findDOMNode: findDOMNode,
  render: ReactMount.render,
  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
  version: ReactVersion,

  /* eslint-disable camelcase */
  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
  unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
  /* eslint-enable camelcase */
};

// Inject the runtime into a devtools global hook regardless of browser.
// Allows for debugging when the hook is injected on the page.
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
    ComponentTree: {
      getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode,
      getNodeFromInstance: function (inst) {
        // inst is an internal instance (but could be a composite)
        if (inst._renderedComponent) {
          inst = getHostComponentFromComposite(inst);
        }
        if (inst) {
          return ReactDOMComponentTree.getNodeFromInstance(inst);
        } else {
          return null;
        }
      }
    },
    Mount: ReactMount,
    Reconciler: ReactReconciler
  });
}

if (true) {
  var ExecutionEnvironment = __webpack_require__(5);
  if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
    // First check if devtools is not installed
    if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
      // If we're in Chrome or Firefox, provide a download link if not installed.
      if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) {
        // Firefox does not have the issue with devtools loaded over file://
        var showFileUrlMessage = window.location.protocol.indexOf('http') === -1 && navigator.userAgent.indexOf('Firefox') === -1;
        console.debug('Download the React DevTools ' + (showFileUrlMessage ? 'and use an HTTP server (instead of a file: URL) ' : '') + 'for a better development experience: ' + 'https://fb.me/react-devtools');
      }
    }

    var testFunc = function testFn() {};
     true ? warning((testFunc.name || testFunc.toString()).indexOf('testFn') !== -1, "It looks like you're using a minified copy of the development build " + 'of React. When deploying React apps to production, make sure to use ' + 'the production build which skips development warnings and is faster. ' + 'See https://fb.me/react-minification for more details.') : void 0;

    // If we're in IE8, check to see if we are in compatibility mode and provide
    // information on preventing compatibility mode
    var ieCompatibilityMode = document.documentMode && document.documentMode < 8;

     true ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '<meta http-equiv="X-UA-Compatible" content="IE=edge" />') : void 0;

    var expectedFeatures = [
    // shims
    Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.trim];

    for (var i = 0; i < expectedFeatures.length; i++) {
      if (!expectedFeatures[i]) {
         true ? warning(false, 'One or more ES5 shims expected by React are not available: ' + 'https://fb.me/react-warning-polyfills') : void 0;
        break;
      }
    }
  }
}

if (true) {
  var ReactInstrumentation = __webpack_require__(7);
  var ReactDOMUnknownPropertyHook = __webpack_require__(187);
  var ReactDOMNullInputValuePropHook = __webpack_require__(188);
  var ReactDOMInvalidARIAHook = __webpack_require__(189);

  ReactInstrumentation.debugTool.addHook(ReactDOMUnknownPropertyHook);
  ReactInstrumentation.debugTool.addHook(ReactDOMNullInputValuePropHook);
  ReactInstrumentation.debugTool.addHook(ReactDOMInvalidARIAHook);
}

module.exports = ReactDOM;

/***/ }),
/* 106 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ARIADOMPropertyConfig = __webpack_require__(107);
var BeforeInputEventPlugin = __webpack_require__(108);
var ChangeEventPlugin = __webpack_require__(112);
var DefaultEventPluginOrder = __webpack_require__(120);
var EnterLeaveEventPlugin = __webpack_require__(121);
var HTMLDOMPropertyConfig = __webpack_require__(122);
var ReactComponentBrowserEnvironment = __webpack_require__(123);
var ReactDOMComponent = __webpack_require__(129);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactDOMEmptyComponent = __webpack_require__(155);
var ReactDOMTreeTraversal = __webpack_require__(156);
var ReactDOMTextComponent = __webpack_require__(157);
var ReactDefaultBatchingStrategy = __webpack_require__(158);
var ReactEventListener = __webpack_require__(159);
var ReactInjection = __webpack_require__(161);
var ReactReconcileTransaction = __webpack_require__(162);
var SVGDOMPropertyConfig = __webpack_require__(168);
var SelectEventPlugin = __webpack_require__(169);
var SimpleEventPlugin = __webpack_require__(170);

var alreadyInjected = false;

function inject() {
  if (alreadyInjected) {
    // TODO: This is currently true because these injections are shared between
    // the client and the server package. They should be built independently
    // and not share any injection state. Then this problem will be solved.
    return;
  }
  alreadyInjected = true;

  ReactInjection.EventEmitter.injectReactEventListener(ReactEventListener);

  /**
   * Inject modules for resolving DOM hierarchy and plugin ordering.
   */
  ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
  ReactInjection.EventPluginUtils.injectComponentTree(ReactDOMComponentTree);
  ReactInjection.EventPluginUtils.injectTreeTraversal(ReactDOMTreeTraversal);

  /**
   * Some important event plugins included by default (without having to require
   * them).
   */
  ReactInjection.EventPluginHub.injectEventPluginsByName({
    SimpleEventPlugin: SimpleEventPlugin,
    EnterLeaveEventPlugin: EnterLeaveEventPlugin,
    ChangeEventPlugin: ChangeEventPlugin,
    SelectEventPlugin: SelectEventPlugin,
    BeforeInputEventPlugin: BeforeInputEventPlugin
  });

  ReactInjection.HostComponent.injectGenericComponentClass(ReactDOMComponent);

  ReactInjection.HostComponent.injectTextComponentClass(ReactDOMTextComponent);

  ReactInjection.DOMProperty.injectDOMPropertyConfig(ARIADOMPropertyConfig);
  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);

  ReactInjection.EmptyComponent.injectEmptyComponentFactory(function (instantiate) {
    return new ReactDOMEmptyComponent(instantiate);
  });

  ReactInjection.Updates.injectReconcileTransaction(ReactReconcileTransaction);
  ReactInjection.Updates.injectBatchingStrategy(ReactDefaultBatchingStrategy);

  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
}

module.exports = {
  inject: inject
};

/***/ }),
/* 107 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ARIADOMPropertyConfig = {
  Properties: {
    // Global States and Properties
    'aria-current': 0, // state
    'aria-details': 0,
    'aria-disabled': 0, // state
    'aria-hidden': 0, // state
    'aria-invalid': 0, // state
    'aria-keyshortcuts': 0,
    'aria-label': 0,
    'aria-roledescription': 0,
    // Widget Attributes
    '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,
    // Live Region Attributes
    'aria-atomic': 0,
    'aria-busy': 0,
    'aria-live': 0,
    'aria-relevant': 0,
    // Drag-and-Drop Attributes
    'aria-dropeffect': 0,
    'aria-grabbed': 0,
    // Relationship Attributes
    '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: {}
};

module.exports = ARIADOMPropertyConfig;

/***/ }),
/* 108 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPropagators = __webpack_require__(20);
var ExecutionEnvironment = __webpack_require__(5);
var FallbackCompositionState = __webpack_require__(109);
var SyntheticCompositionEvent = __webpack_require__(110);
var SyntheticInputEvent = __webpack_require__(111);

var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
var START_KEYCODE = 229;

var canUseCompositionEvent = ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window;

var documentMode = null;
if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
  documentMode = document.documentMode;
}

// Webkit offers a very useful `textInput` event that can be used to
// directly represent `beforeInput`. The IE `textinput` event is not as
// useful, so we don't use it.
var canUseTextInputEvent = ExecutionEnvironment.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto();

// In IE9+, we have access to composition events, but the data supplied
// by the native compositionend event may be incorrect. Japanese ideographic
// spaces, for instance (\u3000) are not recorded correctly.
var useFallbackCompositionData = ExecutionEnvironment.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11);

/**
 * Opera <= 12 includes TextEvent in window, but does not fire
 * text input events. Rely on keypress instead.
 */
function isPresto() {
  var opera = window.opera;
  return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12;
}

var SPACEBAR_CODE = 32;
var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);

// Events and their corresponding property names.
var eventTypes = {
  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']
  }
};

// Track whether we've ever handled a keypress on the space key.
var hasSpaceKeypress = false;

/**
 * Return whether a native keypress event is assumed to be a command.
 * This is required because Firefox fires `keypress` events for key commands
 * (cut, copy, select-all, etc.) even though no character is inserted.
 */
function isKeypressCommand(nativeEvent) {
  return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
  // ctrlKey && altKey is equivalent to AltGr, and is not a command.
  !(nativeEvent.ctrlKey && nativeEvent.altKey);
}

/**
 * Translate native top level events into event types.
 *
 * @param {string} topLevelType
 * @return {object}
 */
function getCompositionEventType(topLevelType) {
  switch (topLevelType) {
    case 'topCompositionStart':
      return eventTypes.compositionStart;
    case 'topCompositionEnd':
      return eventTypes.compositionEnd;
    case 'topCompositionUpdate':
      return eventTypes.compositionUpdate;
  }
}

/**
 * Does our fallback best-guess model think this event signifies that
 * composition has begun?
 *
 * @param {string} topLevelType
 * @param {object} nativeEvent
 * @return {boolean}
 */
function isFallbackCompositionStart(topLevelType, nativeEvent) {
  return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE;
}

/**
 * Does our fallback mode think that this event is the end of composition?
 *
 * @param {string} topLevelType
 * @param {object} nativeEvent
 * @return {boolean}
 */
function isFallbackCompositionEnd(topLevelType, nativeEvent) {
  switch (topLevelType) {
    case 'topKeyUp':
      // Command keys insert or clear IME input.
      return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
    case 'topKeyDown':
      // Expect IME keyCode on each keydown. If we get any other
      // code we must have exited earlier.
      return nativeEvent.keyCode !== START_KEYCODE;
    case 'topKeyPress':
    case 'topMouseDown':
    case 'topBlur':
      // Events are not possible without cancelling IME.
      return true;
    default:
      return false;
  }
}

/**
 * Google Input Tools provides composition data via a CustomEvent,
 * with the `data` property populated in the `detail` object. If this
 * is available on the event object, use it. If not, this is a plain
 * composition event and we have nothing special to extract.
 *
 * @param {object} nativeEvent
 * @return {?string}
 */
function getDataFromCustomEvent(nativeEvent) {
  var detail = nativeEvent.detail;
  if (typeof detail === 'object' && 'data' in detail) {
    return detail.data;
  }
  return null;
}

// Track the current IME composition fallback object, if any.
var currentComposition = null;

/**
 * @return {?object} A SyntheticCompositionEvent.
 */
function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
  var eventType;
  var fallbackData;

  if (canUseCompositionEvent) {
    eventType = getCompositionEventType(topLevelType);
  } else if (!currentComposition) {
    if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
      eventType = eventTypes.compositionStart;
    }
  } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
    eventType = eventTypes.compositionEnd;
  }

  if (!eventType) {
    return null;
  }

  if (useFallbackCompositionData) {
    // The current composition is stored statically and must not be
    // overwritten while composition continues.
    if (!currentComposition && eventType === eventTypes.compositionStart) {
      currentComposition = FallbackCompositionState.getPooled(nativeEventTarget);
    } else if (eventType === eventTypes.compositionEnd) {
      if (currentComposition) {
        fallbackData = currentComposition.getData();
      }
    }
  }

  var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget);

  if (fallbackData) {
    // Inject data generated from fallback path into the synthetic event.
    // This matches the property of native CompositionEventInterface.
    event.data = fallbackData;
  } else {
    var customData = getDataFromCustomEvent(nativeEvent);
    if (customData !== null) {
      event.data = customData;
    }
  }

  EventPropagators.accumulateTwoPhaseDispatches(event);
  return event;
}

/**
 * @param {string} topLevelType Record from `EventConstants`.
 * @param {object} nativeEvent Native browser event.
 * @return {?string} The string corresponding to this `beforeInput` event.
 */
function getNativeBeforeInputChars(topLevelType, nativeEvent) {
  switch (topLevelType) {
    case 'topCompositionEnd':
      return getDataFromCustomEvent(nativeEvent);
    case 'topKeyPress':
      /**
       * If native `textInput` events are available, our goal is to make
       * use of them. However, there is a special case: the spacebar key.
       * In Webkit, preventing default on a spacebar `textInput` event
       * cancels character insertion, but it *also* causes the browser
       * to fall back to its default spacebar behavior of scrolling the
       * page.
       *
       * Tracking at:
       * https://code.google.com/p/chromium/issues/detail?id=355103
       *
       * To avoid this issue, use the keypress event as if no `textInput`
       * event is available.
       */
      var which = nativeEvent.which;
      if (which !== SPACEBAR_CODE) {
        return null;
      }

      hasSpaceKeypress = true;
      return SPACEBAR_CHAR;

    case 'topTextInput':
      // Record the characters to be added to the DOM.
      var chars = nativeEvent.data;

      // If it's a spacebar character, assume that we have already handled
      // it at the keypress level and bail immediately. Android Chrome
      // doesn't give us keycodes, so we need to blacklist it.
      if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
        return null;
      }

      return chars;

    default:
      // For other native event types, do nothing.
      return null;
  }
}

/**
 * For browsers that do not provide the `textInput` event, extract the
 * appropriate string to use for SyntheticInputEvent.
 *
 * @param {string} topLevelType Record from `EventConstants`.
 * @param {object} nativeEvent Native browser event.
 * @return {?string} The fallback string for this `beforeInput` event.
 */
function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
  // If we are currently composing (IME) and using a fallback to do so,
  // try to extract the composed characters from the fallback object.
  // If composition event is available, we extract a string only at
  // compositionevent, otherwise extract it at fallback events.
  if (currentComposition) {
    if (topLevelType === 'topCompositionEnd' || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) {
      var chars = currentComposition.getData();
      FallbackCompositionState.release(currentComposition);
      currentComposition = null;
      return chars;
    }
    return null;
  }

  switch (topLevelType) {
    case 'topPaste':
      // If a paste event occurs after a keypress, throw out the input
      // chars. Paste events should not lead to BeforeInput events.
      return null;
    case 'topKeyPress':
      /**
       * As of v27, Firefox may fire keypress events even when no character
       * will be inserted. A few possibilities:
       *
       * - `which` is `0`. Arrow keys, Esc key, etc.
       *
       * - `which` is the pressed key code, but no char is available.
       *   Ex: 'AltGr + d` in Polish. There is no modified character for
       *   this key combination and no character is inserted into the
       *   document, but FF fires the keypress for char code `100` anyway.
       *   No `input` event will occur.
       *
       * - `which` is the pressed key code, but a command combination is
       *   being used. Ex: `Cmd+C`. No character is inserted, and no
       *   `input` event will occur.
       */
      if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
        return String.fromCharCode(nativeEvent.which);
      }
      return null;
    case 'topCompositionEnd':
      return useFallbackCompositionData ? null : nativeEvent.data;
    default:
      return null;
  }
}

/**
 * Extract a SyntheticInputEvent for `beforeInput`, based on either native
 * `textInput` or fallback behavior.
 *
 * @return {?object} A SyntheticInputEvent.
 */
function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
  var chars;

  if (canUseTextInputEvent) {
    chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
  } else {
    chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
  }

  // If no characters are being inserted, no BeforeInput event should
  // be fired.
  if (!chars) {
    return null;
  }

  var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget);

  event.data = chars;
  EventPropagators.accumulateTwoPhaseDispatches(event);
  return event;
}

/**
 * Create an `onBeforeInput` event to match
 * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
 *
 * This event plugin is based on the native `textInput` event
 * available in Chrome, Safari, Opera, and IE. This event fires after
 * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
 *
 * `beforeInput` is spec'd but not implemented in any browsers, and
 * the `input` event does not provide any useful information about what has
 * actually been added, contrary to the spec. Thus, `textInput` is the best
 * available event to identify the characters that have actually been inserted
 * into the target node.
 *
 * This plugin is also responsible for emitting `composition` events, thus
 * allowing us to share composition fallback code for both `beforeInput` and
 * `composition` event types.
 */
var BeforeInputEventPlugin = {
  eventTypes: eventTypes,

  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    return [extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget)];
  }
};

module.exports = BeforeInputEventPlugin;

/***/ }),
/* 109 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var PooledClass = __webpack_require__(15);

var getTextContentAccessor = __webpack_require__(62);

/**
 * This helper class stores information about text content of a target node,
 * allowing comparison of content before and after a given event.
 *
 * Identify the node where selection currently begins, then observe
 * both its text content and its current position in the DOM. Since the
 * browser may natively replace the target node during composition, we can
 * use its position to find its replacement.
 *
 * @param {DOMEventTarget} root
 */
function FallbackCompositionState(root) {
  this._root = root;
  this._startText = this.getText();
  this._fallbackText = null;
}

_assign(FallbackCompositionState.prototype, {
  destructor: function () {
    this._root = null;
    this._startText = null;
    this._fallbackText = null;
  },

  /**
   * Get current text of input.
   *
   * @return {string}
   */
  getText: function () {
    if ('value' in this._root) {
      return this._root.value;
    }
    return this._root[getTextContentAccessor()];
  },

  /**
   * Determine the differing substring between the initially stored
   * text content and the current content.
   *
   * @return {string}
   */
  getData: function () {
    if (this._fallbackText) {
      return this._fallbackText;
    }

    var start;
    var startValue = this._startText;
    var startLength = startValue.length;
    var end;
    var endValue = this.getText();
    var endLength = endValue.length;

    for (start = 0; start < startLength; start++) {
      if (startValue[start] !== endValue[start]) {
        break;
      }
    }

    var minEnd = startLength - start;
    for (end = 1; end <= minEnd; end++) {
      if (startValue[startLength - end] !== endValue[endLength - end]) {
        break;
      }
    }

    var sliceTail = end > 1 ? 1 - end : undefined;
    this._fallbackText = endValue.slice(start, sliceTail);
    return this._fallbackText;
  }
});

PooledClass.addPoolingTo(FallbackCompositionState);

module.exports = FallbackCompositionState;

/***/ }),
/* 110 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

/**
 * @interface Event
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
 */
var CompositionEventInterface = {
  data: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticCompositionEvent, CompositionEventInterface);

module.exports = SyntheticCompositionEvent;

/***/ }),
/* 111 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

/**
 * @interface Event
 * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
 *      /#events-inputevents
 */
var InputEventInterface = {
  data: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticInputEvent, InputEventInterface);

module.exports = SyntheticInputEvent;

/***/ }),
/* 112 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPluginHub = __webpack_require__(21);
var EventPropagators = __webpack_require__(20);
var ExecutionEnvironment = __webpack_require__(5);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactUpdates = __webpack_require__(10);
var SyntheticEvent = __webpack_require__(12);

var inputValueTracking = __webpack_require__(65);
var getEventTarget = __webpack_require__(38);
var isEventSupported = __webpack_require__(39);
var isTextInputElement = __webpack_require__(66);

var eventTypes = {
  change: {
    phasedRegistrationNames: {
      bubbled: 'onChange',
      captured: 'onChangeCapture'
    },
    dependencies: ['topBlur', 'topChange', 'topClick', 'topFocus', 'topInput', 'topKeyDown', 'topKeyUp', 'topSelectionChange']
  }
};

function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
  var event = SyntheticEvent.getPooled(eventTypes.change, inst, nativeEvent, target);
  event.type = 'change';
  EventPropagators.accumulateTwoPhaseDispatches(event);
  return event;
}
/**
 * For IE shims
 */
var activeElement = null;
var activeElementInst = null;

/**
 * SECTION: handle `change` event
 */
function shouldUseChangeEvent(elem) {
  var nodeName = elem.nodeName && elem.nodeName.toLowerCase();
  return nodeName === 'select' || nodeName === 'input' && elem.type === 'file';
}

var doesChangeEventBubble = false;
if (ExecutionEnvironment.canUseDOM) {
  // See `handleChange` comment below
  doesChangeEventBubble = isEventSupported('change') && (!document.documentMode || document.documentMode > 8);
}

function manualDispatchChangeEvent(nativeEvent) {
  var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent));

  // If change and propertychange bubbled, we'd just bind to it like all the
  // other events and have it go through ReactBrowserEventEmitter. Since it
  // doesn't, we manually listen for the events and so we have to enqueue and
  // process the abstract event manually.
  //
  // Batching is necessary here in order to ensure that all event handlers run
  // before the next rerender (including event handlers attached to ancestor
  // elements instead of directly on the input). Without this, controlled
  // components don't work properly in conjunction with event bubbling because
  // the component is rerendered and the value reverted before all the event
  // handlers can run. See https://github.com/facebook/react/issues/708.
  ReactUpdates.batchedUpdates(runEventInBatch, event);
}

function runEventInBatch(event) {
  EventPluginHub.enqueueEvents(event);
  EventPluginHub.processEventQueue(false);
}

function startWatchingForChangeEventIE8(target, targetInst) {
  activeElement = target;
  activeElementInst = targetInst;
  activeElement.attachEvent('onchange', manualDispatchChangeEvent);
}

function stopWatchingForChangeEventIE8() {
  if (!activeElement) {
    return;
  }
  activeElement.detachEvent('onchange', manualDispatchChangeEvent);
  activeElement = null;
  activeElementInst = null;
}

function getInstIfValueChanged(targetInst, nativeEvent) {
  var updated = inputValueTracking.updateValueIfChanged(targetInst);
  var simulated = nativeEvent.simulated === true && ChangeEventPlugin._allowSimulatedPassThrough;

  if (updated || simulated) {
    return targetInst;
  }
}

function getTargetInstForChangeEvent(topLevelType, targetInst) {
  if (topLevelType === 'topChange') {
    return targetInst;
  }
}

function handleEventsForChangeEventIE8(topLevelType, target, targetInst) {
  if (topLevelType === 'topFocus') {
    // stopWatching() should be a noop here but we call it just in case we
    // missed a blur event somehow.
    stopWatchingForChangeEventIE8();
    startWatchingForChangeEventIE8(target, targetInst);
  } else if (topLevelType === 'topBlur') {
    stopWatchingForChangeEventIE8();
  }
}

/**
 * SECTION: handle `input` event
 */
var isInputEventSupported = false;
if (ExecutionEnvironment.canUseDOM) {
  // IE9 claims to support the input event but fails to trigger it when
  // deleting text, so we ignore its input events.

  isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9);
}

/**
 * (For IE <=9) Starts tracking propertychange events on the passed-in element
 * and override the value property so that we can distinguish user events from
 * value changes in JS.
 */
function startWatchingForValueChange(target, targetInst) {
  activeElement = target;
  activeElementInst = targetInst;
  activeElement.attachEvent('onpropertychange', handlePropertyChange);
}

/**
 * (For IE <=9) Removes the event listeners from the currently-tracked element,
 * if any exists.
 */
function stopWatchingForValueChange() {
  if (!activeElement) {
    return;
  }
  activeElement.detachEvent('onpropertychange', handlePropertyChange);

  activeElement = null;
  activeElementInst = null;
}

/**
 * (For IE <=9) Handles a propertychange event, sending a `change` event if
 * the value of the active element has changed.
 */
function handlePropertyChange(nativeEvent) {
  if (nativeEvent.propertyName !== 'value') {
    return;
  }
  if (getInstIfValueChanged(activeElementInst, nativeEvent)) {
    manualDispatchChangeEvent(nativeEvent);
  }
}

function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
  if (topLevelType === 'topFocus') {
    // In IE8, we can capture almost all .value changes by adding a
    // propertychange handler and looking for events with propertyName
    // equal to 'value'
    // In IE9, propertychange fires for most input events but is buggy and
    // doesn't fire when text is deleted, but conveniently, selectionchange
    // appears to fire in all of the remaining cases so we catch those and
    // forward the event if the value has changed
    // In either case, we don't want to call the event handler if the value
    // is changed from JS so we redefine a setter for `.value` that updates
    // our activeElementValue variable, allowing us to ignore those changes
    //
    // stopWatching() should be a noop here but we call it just in case we
    // missed a blur event somehow.
    stopWatchingForValueChange();
    startWatchingForValueChange(target, targetInst);
  } else if (topLevelType === 'topBlur') {
    stopWatchingForValueChange();
  }
}

// For IE8 and IE9.
function getTargetInstForInputEventPolyfill(topLevelType, targetInst, nativeEvent) {
  if (topLevelType === 'topSelectionChange' || topLevelType === 'topKeyUp' || topLevelType === 'topKeyDown') {
    // On the selectionchange event, the target is just document which isn't
    // helpful for us so just check activeElement instead.
    //
    // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
    // propertychange on the first input event after setting `value` from a
    // script and fires only keydown, keypress, keyup. Catching keyup usually
    // gets it and catching keydown lets us fire an event for the first
    // keystroke if user does a key repeat (it'll be a little delayed: right
    // before the second keystroke). Other input methods (e.g., paste) seem to
    // fire selectionchange normally.
    return getInstIfValueChanged(activeElementInst, nativeEvent);
  }
}

/**
 * SECTION: handle `click` event
 */
function shouldUseClickEvent(elem) {
  // Use the `click` event to detect changes to checkbox and radio inputs.
  // This approach works across all browsers, whereas `change` does not fire
  // until `blur` in IE8.
  var nodeName = elem.nodeName;
  return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio');
}

function getTargetInstForClickEvent(topLevelType, targetInst, nativeEvent) {
  if (topLevelType === 'topClick') {
    return getInstIfValueChanged(targetInst, nativeEvent);
  }
}

function getTargetInstForInputOrChangeEvent(topLevelType, targetInst, nativeEvent) {
  if (topLevelType === 'topInput' || topLevelType === 'topChange') {
    return getInstIfValueChanged(targetInst, nativeEvent);
  }
}

function handleControlledInputBlur(inst, node) {
  // TODO: In IE, inst is occasionally null. Why?
  if (inst == null) {
    return;
  }

  // Fiber and ReactDOM keep wrapper state in separate places
  var state = inst._wrapperState || node._wrapperState;

  if (!state || !state.controlled || node.type !== 'number') {
    return;
  }

  // If controlled, assign the value attribute to the current value on blur
  var value = '' + node.value;
  if (node.getAttribute('value') !== value) {
    node.setAttribute('value', value);
  }
}

/**
 * This plugin creates an `onChange` event that normalizes change events
 * across form elements. This event fires at a time when it's possible to
 * change the element's value without seeing a flicker.
 *
 * Supported elements are:
 * - input (see `isTextInputElement`)
 * - textarea
 * - select
 */
var ChangeEventPlugin = {
  eventTypes: eventTypes,

  _allowSimulatedPassThrough: true,
  _isInputEventSupported: isInputEventSupported,

  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    var targetNode = targetInst ? ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;

    var getTargetInstFunc, handleEventFunc;
    if (shouldUseChangeEvent(targetNode)) {
      if (doesChangeEventBubble) {
        getTargetInstFunc = getTargetInstForChangeEvent;
      } else {
        handleEventFunc = handleEventsForChangeEventIE8;
      }
    } else if (isTextInputElement(targetNode)) {
      if (isInputEventSupported) {
        getTargetInstFunc = getTargetInstForInputOrChangeEvent;
      } else {
        getTargetInstFunc = getTargetInstForInputEventPolyfill;
        handleEventFunc = handleEventsForInputEventPolyfill;
      }
    } else if (shouldUseClickEvent(targetNode)) {
      getTargetInstFunc = getTargetInstForClickEvent;
    }

    if (getTargetInstFunc) {
      var inst = getTargetInstFunc(topLevelType, targetInst, nativeEvent);
      if (inst) {
        var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget);
        return event;
      }
    }

    if (handleEventFunc) {
      handleEventFunc(topLevelType, targetNode, targetInst);
    }

    // When blurring, set the value attribute for number inputs
    if (topLevelType === 'topBlur') {
      handleControlledInputBlur(targetInst, targetNode);
    }
  }
};

module.exports = ChangeEventPlugin;

/***/ }),
/* 113 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactOwner = __webpack_require__(114);

var ReactRef = {};

function attachRef(ref, component, owner) {
  if (typeof ref === 'function') {
    ref(component.getPublicInstance());
  } else {
    // Legacy ref
    ReactOwner.addComponentAsRefTo(component, ref, owner);
  }
}

function detachRef(ref, component, owner) {
  if (typeof ref === 'function') {
    ref(null);
  } else {
    // Legacy ref
    ReactOwner.removeComponentAsRefFrom(component, ref, owner);
  }
}

ReactRef.attachRefs = function (instance, element) {
  if (element === null || typeof element !== 'object') {
    return;
  }
  var ref = element.ref;
  if (ref != null) {
    attachRef(ref, instance, element._owner);
  }
};

ReactRef.shouldUpdateRefs = function (prevElement, nextElement) {
  // If either the owner or a `ref` has changed, make sure the newest owner
  // has stored a reference to `this`, and the previous owner (if different)
  // has forgotten the reference to `this`. We use the element instead
  // of the public this.props because the post processing cannot determine
  // a ref. The ref conceptually lives on the element.

  // TODO: Should this even be possible? The owner cannot change because
  // it's forbidden by shouldUpdateReactComponent. The ref can change
  // if you swap the keys of but not the refs. Reconsider where this check
  // is made. It probably belongs where the key checking and
  // instantiateReactComponent is done.

  var prevRef = null;
  var prevOwner = null;
  if (prevElement !== null && typeof prevElement === 'object') {
    prevRef = prevElement.ref;
    prevOwner = prevElement._owner;
  }

  var nextRef = null;
  var nextOwner = null;
  if (nextElement !== null && typeof nextElement === 'object') {
    nextRef = nextElement.ref;
    nextOwner = nextElement._owner;
  }

  return prevRef !== nextRef ||
  // If owner changes but we have an unchanged function ref, don't update refs
  typeof nextRef === 'string' && nextOwner !== prevOwner;
};

ReactRef.detachRefs = function (instance, element) {
  if (element === null || typeof element !== 'object') {
    return;
  }
  var ref = element.ref;
  if (ref != null) {
    detachRef(ref, instance, element._owner);
  }
};

module.exports = ReactRef;

/***/ }),
/* 114 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

/**
 * @param {?object} object
 * @return {boolean} True if `object` is a valid owner.
 * @final
 */
function isValidOwner(object) {
  return !!(object && typeof object.attachRef === 'function' && typeof object.detachRef === 'function');
}

/**
 * ReactOwners are capable of storing references to owned components.
 *
 * All components are capable of //being// referenced by owner components, but
 * only ReactOwner components are capable of //referencing// owned components.
 * The named reference is known as a "ref".
 *
 * Refs are available when mounted and updated during reconciliation.
 *
 *   var MyComponent = React.createClass({
 *     render: function() {
 *       return (
 *         <div onClick={this.handleClick}>
 *           <CustomComponent ref="custom" />
 *         </div>
 *       );
 *     },
 *     handleClick: function() {
 *       this.refs.custom.handleClick();
 *     },
 *     componentDidMount: function() {
 *       this.refs.custom.initialize();
 *     }
 *   });
 *
 * Refs should rarely be used. When refs are used, they should only be done to
 * control data that is not handled by React's data flow.
 *
 * @class ReactOwner
 */
var ReactOwner = {
  /**
   * Adds a component by ref to an owner component.
   *
   * @param {ReactComponent} component Component to reference.
   * @param {string} ref Name by which to refer to the component.
   * @param {ReactOwner} owner Component on which to record the ref.
   * @final
   * @internal
   */
  addComponentAsRefTo: function (component, ref, owner) {
    !isValidOwner(owner) ?  true ? invariant(false, 'addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component\'s `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).') : _prodInvariant('119') : void 0;
    owner.attachRef(ref, component);
  },

  /**
   * Removes a component by ref from an owner component.
   *
   * @param {ReactComponent} component Component to dereference.
   * @param {string} ref Name of the ref to remove.
   * @param {ReactOwner} owner Component on which the ref is recorded.
   * @final
   * @internal
   */
  removeComponentAsRefFrom: function (component, ref, owner) {
    !isValidOwner(owner) ?  true ? invariant(false, 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component\'s `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).') : _prodInvariant('120') : void 0;
    var ownerPublicInstance = owner.getPublicInstance();
    // Check that `component`'s owner is still alive and that `component` is still the current ref
    // because we do not want to detach the ref if another component stole it.
    if (ownerPublicInstance && ownerPublicInstance.refs[ref] === component.getPublicInstance()) {
      owner.detachRef(ref);
    }
  }
};

module.exports = ReactOwner;

/***/ }),
/* 115 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactInvalidSetStateWarningHook = __webpack_require__(116);
var ReactHostOperationHistoryHook = __webpack_require__(117);
var ReactComponentTreeHook = __webpack_require__(6);
var ExecutionEnvironment = __webpack_require__(5);

var performanceNow = __webpack_require__(118);
var warning = __webpack_require__(1);

var hooks = [];
var didHookThrowForEvent = {};

function callHook(event, fn, context, arg1, arg2, arg3, arg4, arg5) {
  try {
    fn.call(context, arg1, arg2, arg3, arg4, arg5);
  } catch (e) {
     true ? warning(didHookThrowForEvent[event], 'Exception thrown by hook while handling %s: %s', event, e + '\n' + e.stack) : void 0;
    didHookThrowForEvent[event] = true;
  }
}

function emitEvent(event, arg1, arg2, arg3, arg4, arg5) {
  for (var i = 0; i < hooks.length; i++) {
    var hook = hooks[i];
    var fn = hook[event];
    if (fn) {
      callHook(event, fn, hook, arg1, arg2, arg3, arg4, arg5);
    }
  }
}

var isProfiling = false;
var flushHistory = [];
var lifeCycleTimerStack = [];
var currentFlushNesting = 0;
var currentFlushMeasurements = [];
var currentFlushStartTime = 0;
var currentTimerDebugID = null;
var currentTimerStartTime = 0;
var currentTimerNestedFlushDuration = 0;
var currentTimerType = null;

var lifeCycleTimerHasWarned = false;

function clearHistory() {
  ReactComponentTreeHook.purgeUnmountedComponents();
  ReactHostOperationHistoryHook.clearHistory();
}

function getTreeSnapshot(registeredIDs) {
  return registeredIDs.reduce(function (tree, id) {
    var ownerID = ReactComponentTreeHook.getOwnerID(id);
    var parentID = ReactComponentTreeHook.getParentID(id);
    tree[id] = {
      displayName: ReactComponentTreeHook.getDisplayName(id),
      text: ReactComponentTreeHook.getText(id),
      updateCount: ReactComponentTreeHook.getUpdateCount(id),
      childIDs: ReactComponentTreeHook.getChildIDs(id),
      // Text nodes don't have owners but this is close enough.
      ownerID: ownerID || parentID && ReactComponentTreeHook.getOwnerID(parentID) || 0,
      parentID: parentID
    };
    return tree;
  }, {});
}

function resetMeasurements() {
  var previousStartTime = currentFlushStartTime;
  var previousMeasurements = currentFlushMeasurements;
  var previousOperations = ReactHostOperationHistoryHook.getHistory();

  if (currentFlushNesting === 0) {
    currentFlushStartTime = 0;
    currentFlushMeasurements = [];
    clearHistory();
    return;
  }

  if (previousMeasurements.length || previousOperations.length) {
    var registeredIDs = ReactComponentTreeHook.getRegisteredIDs();
    flushHistory.push({
      duration: performanceNow() - previousStartTime,
      measurements: previousMeasurements || [],
      operations: previousOperations || [],
      treeSnapshot: getTreeSnapshot(registeredIDs)
    });
  }

  clearHistory();
  currentFlushStartTime = performanceNow();
  currentFlushMeasurements = [];
}

function checkDebugID(debugID) {
  var allowRoot = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

  if (allowRoot && debugID === 0) {
    return;
  }
  if (!debugID) {
     true ? warning(false, 'ReactDebugTool: debugID may not be empty.') : void 0;
  }
}

function beginLifeCycleTimer(debugID, timerType) {
  if (currentFlushNesting === 0) {
    return;
  }
  if (currentTimerType && !lifeCycleTimerHasWarned) {
     true ? warning(false, 'There is an internal error in the React performance measurement code. ' + 'Did not expect %s timer to start while %s timer is still in ' + 'progress for %s instance.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0;
    lifeCycleTimerHasWarned = true;
  }
  currentTimerStartTime = performanceNow();
  currentTimerNestedFlushDuration = 0;
  currentTimerDebugID = debugID;
  currentTimerType = timerType;
}

function endLifeCycleTimer(debugID, timerType) {
  if (currentFlushNesting === 0) {
    return;
  }
  if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) {
     true ? warning(false, 'There is an internal error in the React performance measurement code. ' + 'We did not expect %s timer to stop while %s timer is still in ' + 'progress for %s instance. Please report this as a bug in React.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0;
    lifeCycleTimerHasWarned = true;
  }
  if (isProfiling) {
    currentFlushMeasurements.push({
      timerType: timerType,
      instanceID: debugID,
      duration: performanceNow() - currentTimerStartTime - currentTimerNestedFlushDuration
    });
  }
  currentTimerStartTime = 0;
  currentTimerNestedFlushDuration = 0;
  currentTimerDebugID = null;
  currentTimerType = null;
}

function pauseCurrentLifeCycleTimer() {
  var currentTimer = {
    startTime: currentTimerStartTime,
    nestedFlushStartTime: performanceNow(),
    debugID: currentTimerDebugID,
    timerType: currentTimerType
  };
  lifeCycleTimerStack.push(currentTimer);
  currentTimerStartTime = 0;
  currentTimerNestedFlushDuration = 0;
  currentTimerDebugID = null;
  currentTimerType = null;
}

function resumeCurrentLifeCycleTimer() {
  var _lifeCycleTimerStack$ = lifeCycleTimerStack.pop(),
      startTime = _lifeCycleTimerStack$.startTime,
      nestedFlushStartTime = _lifeCycleTimerStack$.nestedFlushStartTime,
      debugID = _lifeCycleTimerStack$.debugID,
      timerType = _lifeCycleTimerStack$.timerType;

  var nestedFlushDuration = performanceNow() - nestedFlushStartTime;
  currentTimerStartTime = startTime;
  currentTimerNestedFlushDuration += nestedFlushDuration;
  currentTimerDebugID = debugID;
  currentTimerType = timerType;
}

var lastMarkTimeStamp = 0;
var canUsePerformanceMeasure = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function';

function shouldMark(debugID) {
  if (!isProfiling || !canUsePerformanceMeasure) {
    return false;
  }
  var element = ReactComponentTreeHook.getElement(debugID);
  if (element == null || typeof element !== 'object') {
    return false;
  }
  var isHostElement = typeof element.type === 'string';
  if (isHostElement) {
    return false;
  }
  return true;
}

function markBegin(debugID, markType) {
  if (!shouldMark(debugID)) {
    return;
  }

  var markName = debugID + '::' + markType;
  lastMarkTimeStamp = performanceNow();
  performance.mark(markName);
}

function markEnd(debugID, markType) {
  if (!shouldMark(debugID)) {
    return;
  }

  var markName = debugID + '::' + markType;
  var displayName = ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown';

  // Chrome has an issue of dropping markers recorded too fast:
  // https://bugs.chromium.org/p/chromium/issues/detail?id=640652
  // To work around this, we will not report very small measurements.
  // I determined the magic number by tweaking it back and forth.
  // 0.05ms was enough to prevent the issue, but I set it to 0.1ms to be safe.
  // When the bug is fixed, we can `measure()` unconditionally if we want to.
  var timeStamp = performanceNow();
  if (timeStamp - lastMarkTimeStamp > 0.1) {
    var measurementName = displayName + ' [' + markType + ']';
    performance.measure(measurementName, markName);
  }

  performance.clearMarks(markName);
  if (measurementName) {
    performance.clearMeasures(measurementName);
  }
}

var ReactDebugTool = {
  addHook: function (hook) {
    hooks.push(hook);
  },
  removeHook: function (hook) {
    for (var i = 0; i < hooks.length; i++) {
      if (hooks[i] === hook) {
        hooks.splice(i, 1);
        i--;
      }
    }
  },
  isProfiling: function () {
    return isProfiling;
  },
  beginProfiling: function () {
    if (isProfiling) {
      return;
    }

    isProfiling = true;
    flushHistory.length = 0;
    resetMeasurements();
    ReactDebugTool.addHook(ReactHostOperationHistoryHook);
  },
  endProfiling: function () {
    if (!isProfiling) {
      return;
    }

    isProfiling = false;
    resetMeasurements();
    ReactDebugTool.removeHook(ReactHostOperationHistoryHook);
  },
  getFlushHistory: function () {
    return flushHistory;
  },
  onBeginFlush: function () {
    currentFlushNesting++;
    resetMeasurements();
    pauseCurrentLifeCycleTimer();
    emitEvent('onBeginFlush');
  },
  onEndFlush: function () {
    resetMeasurements();
    currentFlushNesting--;
    resumeCurrentLifeCycleTimer();
    emitEvent('onEndFlush');
  },
  onBeginLifeCycleTimer: function (debugID, timerType) {
    checkDebugID(debugID);
    emitEvent('onBeginLifeCycleTimer', debugID, timerType);
    markBegin(debugID, timerType);
    beginLifeCycleTimer(debugID, timerType);
  },
  onEndLifeCycleTimer: function (debugID, timerType) {
    checkDebugID(debugID);
    endLifeCycleTimer(debugID, timerType);
    markEnd(debugID, timerType);
    emitEvent('onEndLifeCycleTimer', debugID, timerType);
  },
  onBeginProcessingChildContext: function () {
    emitEvent('onBeginProcessingChildContext');
  },
  onEndProcessingChildContext: function () {
    emitEvent('onEndProcessingChildContext');
  },
  onHostOperation: function (operation) {
    checkDebugID(operation.instanceID);
    emitEvent('onHostOperation', operation);
  },
  onSetState: function () {
    emitEvent('onSetState');
  },
  onSetChildren: function (debugID, childDebugIDs) {
    checkDebugID(debugID);
    childDebugIDs.forEach(checkDebugID);
    emitEvent('onSetChildren', debugID, childDebugIDs);
  },
  onBeforeMountComponent: function (debugID, element, parentDebugID) {
    checkDebugID(debugID);
    checkDebugID(parentDebugID, true);
    emitEvent('onBeforeMountComponent', debugID, element, parentDebugID);
    markBegin(debugID, 'mount');
  },
  onMountComponent: function (debugID) {
    checkDebugID(debugID);
    markEnd(debugID, 'mount');
    emitEvent('onMountComponent', debugID);
  },
  onBeforeUpdateComponent: function (debugID, element) {
    checkDebugID(debugID);
    emitEvent('onBeforeUpdateComponent', debugID, element);
    markBegin(debugID, 'update');
  },
  onUpdateComponent: function (debugID) {
    checkDebugID(debugID);
    markEnd(debugID, 'update');
    emitEvent('onUpdateComponent', debugID);
  },
  onBeforeUnmountComponent: function (debugID) {
    checkDebugID(debugID);
    emitEvent('onBeforeUnmountComponent', debugID);
    markBegin(debugID, 'unmount');
  },
  onUnmountComponent: function (debugID) {
    checkDebugID(debugID);
    markEnd(debugID, 'unmount');
    emitEvent('onUnmountComponent', debugID);
  },
  onTestEvent: function () {
    emitEvent('onTestEvent');
  }
};

// TODO remove these when RN/www gets updated
ReactDebugTool.addDevtool = ReactDebugTool.addHook;
ReactDebugTool.removeDevtool = ReactDebugTool.removeHook;

ReactDebugTool.addHook(ReactInvalidSetStateWarningHook);
ReactDebugTool.addHook(ReactComponentTreeHook);
var url = ExecutionEnvironment.canUseDOM && window.location.href || '';
if (/[?&]react_perf\b/.test(url)) {
  ReactDebugTool.beginProfiling();
}

module.exports = ReactDebugTool;

/***/ }),
/* 116 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var warning = __webpack_require__(1);

if (true) {
  var processingChildContext = false;

  var warnInvalidSetState = function () {
     true ? warning(!processingChildContext, 'setState(...): Cannot call setState() inside getChildContext()') : void 0;
  };
}

var ReactInvalidSetStateWarningHook = {
  onBeginProcessingChildContext: function () {
    processingChildContext = true;
  },
  onEndProcessingChildContext: function () {
    processingChildContext = false;
  },
  onSetState: function () {
    warnInvalidSetState();
  }
};

module.exports = ReactInvalidSetStateWarningHook;

/***/ }),
/* 117 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var history = [];

var ReactHostOperationHistoryHook = {
  onHostOperation: function (operation) {
    history.push(operation);
  },
  clearHistory: function () {
    if (ReactHostOperationHistoryHook._preventClearing) {
      // Should only be used for tests.
      return;
    }

    history = [];
  },
  getHistory: function () {
    return history;
  }
};

module.exports = ReactHostOperationHistoryHook;

/***/ }),
/* 118 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var performance = __webpack_require__(119);

var performanceNow;

/**
 * Detect if we can use `window.performance.now()` and gracefully fallback to
 * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
 * because of Facebook's testing infrastructure.
 */
if (performance.now) {
  performanceNow = function performanceNow() {
    return performance.now();
  };
} else {
  performanceNow = function performanceNow() {
    return Date.now();
  };
}

module.exports = performanceNow;

/***/ }),
/* 119 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */



var ExecutionEnvironment = __webpack_require__(5);

var performance;

if (ExecutionEnvironment.canUseDOM) {
  performance = window.performance || window.msPerformance || window.webkitPerformance;
}

module.exports = performance || {};

/***/ }),
/* 120 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Module that is injectable into `EventPluginHub`, that specifies a
 * deterministic ordering of `EventPlugin`s. A convenient way to reason about
 * plugins, without having to package every one of them. This is better than
 * having plugins be ordered in the same order that they are injected because
 * that ordering would be influenced by the packaging order.
 * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
 * preventing default on events is convenient in `SimpleEventPlugin` handlers.
 */

var DefaultEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'TapEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin'];

module.exports = DefaultEventPluginOrder;

/***/ }),
/* 121 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPropagators = __webpack_require__(20);
var ReactDOMComponentTree = __webpack_require__(4);
var SyntheticMouseEvent = __webpack_require__(30);

var eventTypes = {
  mouseEnter: {
    registrationName: 'onMouseEnter',
    dependencies: ['topMouseOut', 'topMouseOver']
  },
  mouseLeave: {
    registrationName: 'onMouseLeave',
    dependencies: ['topMouseOut', 'topMouseOver']
  }
};

var EnterLeaveEventPlugin = {
  eventTypes: eventTypes,

  /**
   * For almost every interaction we care about, there will be both a top-level
   * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
   * we do not extract duplicate events. However, moving the mouse into the
   * browser from outside will not fire a `mouseout` event. In this case, we use
   * the `mouseover` top-level event.
   */
  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    if (topLevelType === 'topMouseOver' && (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
      return null;
    }
    if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') {
      // Must not be a mouse in or mouse out - ignoring.
      return null;
    }

    var win;
    if (nativeEventTarget.window === nativeEventTarget) {
      // `nativeEventTarget` is probably a window object.
      win = nativeEventTarget;
    } else {
      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
      var doc = nativeEventTarget.ownerDocument;
      if (doc) {
        win = doc.defaultView || doc.parentWindow;
      } else {
        win = window;
      }
    }

    var from;
    var to;
    if (topLevelType === 'topMouseOut') {
      from = targetInst;
      var related = nativeEvent.relatedTarget || nativeEvent.toElement;
      to = related ? ReactDOMComponentTree.getClosestInstanceFromNode(related) : null;
    } else {
      // Moving to a node from outside the window.
      from = null;
      to = targetInst;
    }

    if (from === to) {
      // Nothing pertains to our managed components.
      return null;
    }

    var fromNode = from == null ? win : ReactDOMComponentTree.getNodeFromInstance(from);
    var toNode = to == null ? win : ReactDOMComponentTree.getNodeFromInstance(to);

    var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, from, nativeEvent, nativeEventTarget);
    leave.type = 'mouseleave';
    leave.target = fromNode;
    leave.relatedTarget = toNode;

    var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, to, nativeEvent, nativeEventTarget);
    enter.type = 'mouseenter';
    enter.target = toNode;
    enter.relatedTarget = fromNode;

    EventPropagators.accumulateEnterLeaveDispatches(leave, enter, from, to);

    return [leave, enter];
  }
};

module.exports = EnterLeaveEventPlugin;

/***/ }),
/* 122 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMProperty = __webpack_require__(13);

var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;

var HTMLDOMPropertyConfig = {
  isCustomAttribute: RegExp.prototype.test.bind(new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')),
  Properties: {
    /**
     * Standard Properties
     */
    accept: 0,
    acceptCharset: 0,
    accessKey: 0,
    action: 0,
    allowFullScreen: HAS_BOOLEAN_VALUE,
    allowTransparency: 0,
    alt: 0,
    // specifies target context for links with `preload` type
    as: 0,
    async: HAS_BOOLEAN_VALUE,
    autoComplete: 0,
    // autoFocus is polyfilled/normalized by AutoFocusUtils
    // autoFocus: HAS_BOOLEAN_VALUE,
    autoPlay: HAS_BOOLEAN_VALUE,
    capture: HAS_BOOLEAN_VALUE,
    cellPadding: 0,
    cellSpacing: 0,
    charSet: 0,
    challenge: 0,
    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    cite: 0,
    classID: 0,
    className: 0,
    cols: HAS_POSITIVE_NUMERIC_VALUE,
    colSpan: 0,
    content: 0,
    contentEditable: 0,
    contextMenu: 0,
    controls: HAS_BOOLEAN_VALUE,
    controlsList: 0,
    coords: 0,
    crossOrigin: 0,
    data: 0, // For `<object />` acts as `src`.
    dateTime: 0,
    'default': HAS_BOOLEAN_VALUE,
    defer: HAS_BOOLEAN_VALUE,
    dir: 0,
    disabled: HAS_BOOLEAN_VALUE,
    download: HAS_OVERLOADED_BOOLEAN_VALUE,
    draggable: 0,
    encType: 0,
    form: 0,
    formAction: 0,
    formEncType: 0,
    formMethod: 0,
    formNoValidate: HAS_BOOLEAN_VALUE,
    formTarget: 0,
    frameBorder: 0,
    headers: 0,
    height: 0,
    hidden: HAS_BOOLEAN_VALUE,
    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: HAS_BOOLEAN_VALUE,
    low: 0,
    manifest: 0,
    marginHeight: 0,
    marginWidth: 0,
    max: 0,
    maxLength: 0,
    media: 0,
    mediaGroup: 0,
    method: 0,
    min: 0,
    minLength: 0,
    // Caution; `option.selected` is not updated if `select.multiple` is
    // disabled with `removeAttribute`.
    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    name: 0,
    nonce: 0,
    noValidate: HAS_BOOLEAN_VALUE,
    open: HAS_BOOLEAN_VALUE,
    optimum: 0,
    pattern: 0,
    placeholder: 0,
    playsInline: HAS_BOOLEAN_VALUE,
    poster: 0,
    preload: 0,
    profile: 0,
    radioGroup: 0,
    readOnly: HAS_BOOLEAN_VALUE,
    referrerPolicy: 0,
    rel: 0,
    required: HAS_BOOLEAN_VALUE,
    reversed: HAS_BOOLEAN_VALUE,
    role: 0,
    rows: HAS_POSITIVE_NUMERIC_VALUE,
    rowSpan: HAS_NUMERIC_VALUE,
    sandbox: 0,
    scope: 0,
    scoped: HAS_BOOLEAN_VALUE,
    scrolling: 0,
    seamless: HAS_BOOLEAN_VALUE,
    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    shape: 0,
    size: HAS_POSITIVE_NUMERIC_VALUE,
    sizes: 0,
    span: HAS_POSITIVE_NUMERIC_VALUE,
    spellCheck: 0,
    src: 0,
    srcDoc: 0,
    srcLang: 0,
    srcSet: 0,
    start: HAS_NUMERIC_VALUE,
    step: 0,
    style: 0,
    summary: 0,
    tabIndex: 0,
    target: 0,
    title: 0,
    // Setting .type throws on non-<input> tags
    type: 0,
    useMap: 0,
    value: 0,
    width: 0,
    wmode: 0,
    wrap: 0,

    /**
     * RDFa Properties
     */
    about: 0,
    datatype: 0,
    inlist: 0,
    prefix: 0,
    // property is also supported for OpenGraph in meta tags.
    property: 0,
    resource: 0,
    'typeof': 0,
    vocab: 0,

    /**
     * Non-standard Properties
     */
    // autoCapitalize and autoCorrect are supported in Mobile Safari for
    // keyboard hints.
    autoCapitalize: 0,
    autoCorrect: 0,
    // autoSave allows WebKit/Blink to persist values of input fields on page reloads
    autoSave: 0,
    // color is for Safari mask-icon link
    color: 0,
    // itemProp, itemScope, itemType are for
    // Microdata support. See http://schema.org/docs/gs.html
    itemProp: 0,
    itemScope: HAS_BOOLEAN_VALUE,
    itemType: 0,
    // itemID and itemRef are for Microdata support as well but
    // only specified in the WHATWG spec document. See
    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
    itemID: 0,
    itemRef: 0,
    // results show looking glass icon and recent searches on input
    // search fields in WebKit/Blink
    results: 0,
    // IE-only attribute that specifies security restrictions on an iframe
    // as an alternative to the sandbox attribute on IE<10
    security: 0,
    // IE-only attribute that controls focus behavior
    unselectable: 0
  },
  DOMAttributeNames: {
    acceptCharset: 'accept-charset',
    className: 'class',
    htmlFor: 'for',
    httpEquiv: 'http-equiv'
  },
  DOMPropertyNames: {},
  DOMMutationMethods: {
    value: function (node, value) {
      if (value == null) {
        return node.removeAttribute('value');
      }

      // Number inputs get special treatment due to some edge cases in
      // Chrome. Let everything else assign the value attribute as normal.
      // https://github.com/facebook/react/issues/7253#issuecomment-236074326
      if (node.type !== 'number' || node.hasAttribute('value') === false) {
        node.setAttribute('value', '' + value);
      } else if (node.validity && !node.validity.badInput && node.ownerDocument.activeElement !== node) {
        // Don't assign an attribute if validation reports bad
        // input. Chrome will clear the value. Additionally, don't
        // operate on inputs that have focus, otherwise Chrome might
        // strip off trailing decimal places and cause the user's
        // cursor position to jump to the beginning of the input.
        //
        // In ReactDOMInput, we have an onBlur event that will trigger
        // this function again when focus is lost.
        node.setAttribute('value', '' + value);
      }
    }
  }
};

module.exports = HTMLDOMPropertyConfig;

/***/ }),
/* 123 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMChildrenOperations = __webpack_require__(41);
var ReactDOMIDOperations = __webpack_require__(128);

/**
 * Abstracts away all functionality of the reconciler that requires knowledge of
 * the browser context. TODO: These callers should be refactored to avoid the
 * need for this injection.
 */
var ReactComponentBrowserEnvironment = {
  processChildrenUpdates: ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,

  replaceNodeWithMarkup: DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup
};

module.exports = ReactComponentBrowserEnvironment;

/***/ }),
/* 124 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var DOMLazyTree = __webpack_require__(19);
var ExecutionEnvironment = __webpack_require__(5);

var createNodesFromMarkup = __webpack_require__(125);
var emptyFunction = __webpack_require__(8);
var invariant = __webpack_require__(0);

var Danger = {
  /**
   * Replaces a node with a string of markup at its current position within its
   * parent. The markup must render into a single root node.
   *
   * @param {DOMElement} oldChild Child node to replace.
   * @param {string} markup Markup to render in place of the child node.
   * @internal
   */
  dangerouslyReplaceNodeWithMarkup: function (oldChild, markup) {
    !ExecutionEnvironment.canUseDOM ?  true ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering.') : _prodInvariant('56') : void 0;
    !markup ?  true ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : _prodInvariant('57') : void 0;
    !(oldChild.nodeName !== 'HTML') ?  true ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the <html> node. This is because browser quirks make this unreliable and/or slow. If you want to render to the root you must use server rendering. See ReactDOMServer.renderToString().') : _prodInvariant('58') : void 0;

    if (typeof markup === 'string') {
      var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
      oldChild.parentNode.replaceChild(newChild, oldChild);
    } else {
      DOMLazyTree.replaceChildWithTree(oldChild, markup);
    }
  }
};

module.exports = Danger;

/***/ }),
/* 125 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

/*eslint-disable fb-www/unsafe-html*/

var ExecutionEnvironment = __webpack_require__(5);

var createArrayFromMixed = __webpack_require__(126);
var getMarkupWrap = __webpack_require__(127);
var invariant = __webpack_require__(0);

/**
 * Dummy container used to render all markup.
 */
var dummyNode = ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;

/**
 * Pattern used by `getNodeName`.
 */
var nodeNamePattern = /^\s*<(\w+)/;

/**
 * Extracts the `nodeName` of the first element in a string of markup.
 *
 * @param {string} markup String of markup.
 * @return {?string} Node name of the supplied markup.
 */
function getNodeName(markup) {
  var nodeNameMatch = markup.match(nodeNamePattern);
  return nodeNameMatch && nodeNameMatch[1].toLowerCase();
}

/**
 * Creates an array containing the nodes rendered from the supplied markup. The
 * optionally supplied `handleScript` function will be invoked once for each
 * <script> element that is rendered. If no `handleScript` function is supplied,
 * an exception is thrown if any <script> elements are rendered.
 *
 * @param {string} markup A string of valid HTML markup.
 * @param {?function} handleScript Invoked once for each rendered <script>.
 * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
 */
function createNodesFromMarkup(markup, handleScript) {
  var node = dummyNode;
  !!!dummyNode ?  true ? invariant(false, 'createNodesFromMarkup dummy not initialized') : invariant(false) : void 0;
  var nodeName = getNodeName(markup);

  var wrap = nodeName && getMarkupWrap(nodeName);
  if (wrap) {
    node.innerHTML = wrap[1] + markup + wrap[2];

    var wrapDepth = wrap[0];
    while (wrapDepth--) {
      node = node.lastChild;
    }
  } else {
    node.innerHTML = markup;
  }

  var scripts = node.getElementsByTagName('script');
  if (scripts.length) {
    !handleScript ?  true ? invariant(false, 'createNodesFromMarkup(...): Unexpected <script> element rendered.') : invariant(false) : void 0;
    createArrayFromMixed(scripts).forEach(handleScript);
  }

  var nodes = Array.from(node.childNodes);
  while (node.lastChild) {
    node.removeChild(node.lastChild);
  }
  return nodes;
}

module.exports = createNodesFromMarkup;

/***/ }),
/* 126 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var invariant = __webpack_require__(0);

/**
 * Convert array-like objects to arrays.
 *
 * This API assumes the caller knows the contents of the data type. For less
 * well defined inputs use createArrayFromMixed.
 *
 * @param {object|function|filelist} obj
 * @return {array}
 */
function toArray(obj) {
  var length = obj.length;

  // Some browsers builtin objects can report typeof 'function' (e.g. NodeList
  // in old versions of Safari).
  !(!Array.isArray(obj) && (typeof obj === 'object' || typeof obj === 'function')) ?  true ? invariant(false, 'toArray: Array-like object expected') : invariant(false) : void 0;

  !(typeof length === 'number') ?  true ? invariant(false, 'toArray: Object needs a length property') : invariant(false) : void 0;

  !(length === 0 || length - 1 in obj) ?  true ? invariant(false, 'toArray: Object should have keys for indices') : invariant(false) : void 0;

  !(typeof obj.callee !== 'function') ?  true ? invariant(false, 'toArray: Object can\'t be `arguments`. Use rest params ' + '(function(...args) {}) or Array.from() instead.') : invariant(false) : void 0;

  // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
  // without method will throw during the slice call and skip straight to the
  // fallback.
  if (obj.hasOwnProperty) {
    try {
      return Array.prototype.slice.call(obj);
    } catch (e) {
      // IE < 9 does not support Array#slice on collections objects
    }
  }

  // Fall back to copying key by key. This assumes all keys have a value,
  // so will not preserve sparsely populated inputs.
  var ret = Array(length);
  for (var ii = 0; ii < length; ii++) {
    ret[ii] = obj[ii];
  }
  return ret;
}

/**
 * Perform a heuristic test to determine if an object is "array-like".
 *
 *   A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
 *   Joshu replied: "Mu."
 *
 * This function determines if its argument has "array nature": it returns
 * true if the argument is an actual array, an `arguments' object, or an
 * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
 *
 * It will return false for other array-like objects like Filelist.
 *
 * @param {*} obj
 * @return {boolean}
 */
function hasArrayNature(obj) {
  return (
    // not null/false
    !!obj && (
    // arrays are objects, NodeLists are functions in Safari
    typeof obj == 'object' || typeof obj == 'function') &&
    // quacks like an array
    'length' in obj &&
    // not window
    !('setInterval' in obj) &&
    // no DOM node should be considered an array-like
    // a 'select' element has 'length' and 'item' properties on IE8
    typeof obj.nodeType != 'number' && (
    // a real array
    Array.isArray(obj) ||
    // arguments
    'callee' in obj ||
    // HTMLCollection/NodeList
    'item' in obj)
  );
}

/**
 * Ensure that the argument is an array by wrapping it in an array if it is not.
 * Creates a copy of the argument if it is already an array.
 *
 * This is mostly useful idiomatically:
 *
 *   var createArrayFromMixed = require('createArrayFromMixed');
 *
 *   function takesOneOrMoreThings(things) {
 *     things = createArrayFromMixed(things);
 *     ...
 *   }
 *
 * This allows you to treat `things' as an array, but accept scalars in the API.
 *
 * If you need to convert an array-like object, like `arguments`, into an array
 * use toArray instead.
 *
 * @param {*} obj
 * @return {array}
 */
function createArrayFromMixed(obj) {
  if (!hasArrayNature(obj)) {
    return [obj];
  } else if (Array.isArray(obj)) {
    return obj.slice();
  } else {
    return toArray(obj);
  }
}

module.exports = createArrayFromMixed;

/***/ }),
/* 127 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/*eslint-disable fb-www/unsafe-html */

var ExecutionEnvironment = __webpack_require__(5);

var invariant = __webpack_require__(0);

/**
 * Dummy container used to detect which wraps are necessary.
 */
var dummyNode = ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;

/**
 * Some browsers cannot use `innerHTML` to render certain elements standalone,
 * so we wrap them, render the wrapped nodes, then extract the desired node.
 *
 * In IE8, certain elements cannot render alone, so wrap all elements ('*').
 */

var shouldWrap = {};

var selectWrap = [1, '<select multiple="true">', '</select>'];
var tableWrap = [1, '<table>', '</table>'];
var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];

var svgWrap = [1, '<svg xmlns="http://www.w3.org/2000/svg">', '</svg>'];

var markupWrap = {
  '*': [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': selectWrap,
  'option': selectWrap,

  'caption': tableWrap,
  'colgroup': tableWrap,
  'tbody': tableWrap,
  'tfoot': tableWrap,
  'thead': tableWrap,

  'td': trWrap,
  'th': trWrap
};

// Initialize the SVG elements since we know they'll always need to be wrapped
// consistently. If they are created inside a <div> they will be initialized in
// the wrong namespace (and will not display).
var svgElements = ['circle', 'clipPath', 'defs', 'ellipse', 'g', 'image', 'line', 'linearGradient', 'mask', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'text', 'tspan'];
svgElements.forEach(function (nodeName) {
  markupWrap[nodeName] = svgWrap;
  shouldWrap[nodeName] = true;
});

/**
 * Gets the markup wrap configuration for the supplied `nodeName`.
 *
 * NOTE: This lazily detects which wraps are necessary for the current browser.
 *
 * @param {string} nodeName Lowercase `nodeName`.
 * @return {?array} Markup wrap configuration, if applicable.
 */
function getMarkupWrap(nodeName) {
  !!!dummyNode ?  true ? invariant(false, 'Markup wrapping node not initialized') : invariant(false) : void 0;
  if (!markupWrap.hasOwnProperty(nodeName)) {
    nodeName = '*';
  }
  if (!shouldWrap.hasOwnProperty(nodeName)) {
    if (nodeName === '*') {
      dummyNode.innerHTML = '<link />';
    } else {
      dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
    }
    shouldWrap[nodeName] = !dummyNode.firstChild;
  }
  return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
}

module.exports = getMarkupWrap;

/***/ }),
/* 128 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMChildrenOperations = __webpack_require__(41);
var ReactDOMComponentTree = __webpack_require__(4);

/**
 * Operations used to process updates to DOM nodes.
 */
var ReactDOMIDOperations = {
  /**
   * Updates a component's children by processing a series of updates.
   *
   * @param {array<object>} updates List of update configurations.
   * @internal
   */
  dangerouslyProcessChildrenUpdates: function (parentInst, updates) {
    var node = ReactDOMComponentTree.getNodeFromInstance(parentInst);
    DOMChildrenOperations.processUpdates(node, updates);
  }
};

module.exports = ReactDOMIDOperations;

/***/ }),
/* 129 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/* global hasOwnProperty:true */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var AutoFocusUtils = __webpack_require__(130);
var CSSPropertyOperations = __webpack_require__(131);
var DOMLazyTree = __webpack_require__(19);
var DOMNamespaces = __webpack_require__(42);
var DOMProperty = __webpack_require__(13);
var DOMPropertyOperations = __webpack_require__(71);
var EventPluginHub = __webpack_require__(21);
var EventPluginRegistry = __webpack_require__(28);
var ReactBrowserEventEmitter = __webpack_require__(33);
var ReactDOMComponentFlags = __webpack_require__(59);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactDOMInput = __webpack_require__(141);
var ReactDOMOption = __webpack_require__(142);
var ReactDOMSelect = __webpack_require__(73);
var ReactDOMTextarea = __webpack_require__(143);
var ReactInstrumentation = __webpack_require__(7);
var ReactMultiChild = __webpack_require__(144);
var ReactServerRenderingTransaction = __webpack_require__(153);

var emptyFunction = __webpack_require__(8);
var escapeTextContentForBrowser = __webpack_require__(32);
var invariant = __webpack_require__(0);
var isEventSupported = __webpack_require__(39);
var shallowEqual = __webpack_require__(46);
var inputValueTracking = __webpack_require__(65);
var validateDOMNesting = __webpack_require__(50);
var warning = __webpack_require__(1);

var Flags = ReactDOMComponentFlags;
var deleteListener = EventPluginHub.deleteListener;
var getNode = ReactDOMComponentTree.getNodeFromInstance;
var listenTo = ReactBrowserEventEmitter.listenTo;
var registrationNameModules = EventPluginRegistry.registrationNameModules;

// For quickly matching children type, to test if can be treated as content.
var CONTENT_TYPES = { string: true, number: true };

var STYLE = 'style';
var HTML = '__html';
var RESERVED_PROPS = {
  children: null,
  dangerouslySetInnerHTML: null,
  suppressContentEditableWarning: null
};

// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE).
var DOC_FRAGMENT_TYPE = 11;

function getDeclarationErrorAddendum(internalInstance) {
  if (internalInstance) {
    var owner = internalInstance._currentElement._owner || null;
    if (owner) {
      var name = owner.getName();
      if (name) {
        return ' This DOM node was rendered by `' + name + '`.';
      }
    }
  }
  return '';
}

function friendlyStringify(obj) {
  if (typeof obj === 'object') {
    if (Array.isArray(obj)) {
      return '[' + obj.map(friendlyStringify).join(', ') + ']';
    } else {
      var pairs = [];
      for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          var keyEscaped = /^[a-z$_][\w$_]*$/i.test(key) ? key : JSON.stringify(key);
          pairs.push(keyEscaped + ': ' + friendlyStringify(obj[key]));
        }
      }
      return '{' + pairs.join(', ') + '}';
    }
  } else if (typeof obj === 'string') {
    return JSON.stringify(obj);
  } else if (typeof obj === 'function') {
    return '[function object]';
  }
  // Differs from JSON.stringify in that undefined because undefined and that
  // inf and nan don't become null
  return String(obj);
}

var styleMutationWarning = {};

function checkAndWarnForMutatedStyle(style1, style2, component) {
  if (style1 == null || style2 == null) {
    return;
  }
  if (shallowEqual(style1, style2)) {
    return;
  }

  var componentName = component._tag;
  var owner = component._currentElement._owner;
  var ownerName;
  if (owner) {
    ownerName = owner.getName();
  }

  var hash = ownerName + '|' + componentName;

  if (styleMutationWarning.hasOwnProperty(hash)) {
    return;
  }

  styleMutationWarning[hash] = true;

   true ? warning(false, '`%s` was passed a style object that has previously been mutated. ' + 'Mutating `style` is deprecated. Consider cloning it beforehand. Check ' + 'the `render` %s. Previous style: %s. Mutated style: %s.', componentName, owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>', friendlyStringify(style1), friendlyStringify(style2)) : void 0;
}

/**
 * @param {object} component
 * @param {?object} props
 */
function assertValidProps(component, props) {
  if (!props) {
    return;
  }
  // Note the use of `==` which checks for null or undefined.
  if (voidElementTags[component._tag]) {
    !(props.children == null && props.dangerouslySetInnerHTML == null) ?  true ? invariant(false, '%s is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.%s', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : _prodInvariant('137', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : void 0;
  }
  if (props.dangerouslySetInnerHTML != null) {
    !(props.children == null) ?  true ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : _prodInvariant('60') : void 0;
    !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ?  true ? invariant(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.') : _prodInvariant('61') : void 0;
  }
  if (true) {
     true ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : void 0;
     true ? warning(props.suppressContentEditableWarning || !props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.') : void 0;
     true ? warning(props.onFocusIn == null && props.onFocusOut == null, 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.') : void 0;
  }
  !(props.style == null || typeof props.style === 'object') ?  true ? invariant(false, 'The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + \'em\'}} when using JSX.%s', getDeclarationErrorAddendum(component)) : _prodInvariant('62', getDeclarationErrorAddendum(component)) : void 0;
}

function enqueuePutListener(inst, registrationName, listener, transaction) {
  if (transaction instanceof ReactServerRenderingTransaction) {
    return;
  }
  if (true) {
    // IE8 has no API for event capturing and the `onScroll` event doesn't
    // bubble.
     true ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), "This browser doesn't support the `onScroll` event") : void 0;
  }
  var containerInfo = inst._hostContainerInfo;
  var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
  var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
  listenTo(registrationName, doc);
  transaction.getReactMountReady().enqueue(putListener, {
    inst: inst,
    registrationName: registrationName,
    listener: listener
  });
}

function putListener() {
  var listenerToPut = this;
  EventPluginHub.putListener(listenerToPut.inst, listenerToPut.registrationName, listenerToPut.listener);
}

function inputPostMount() {
  var inst = this;
  ReactDOMInput.postMountWrapper(inst);
}

function textareaPostMount() {
  var inst = this;
  ReactDOMTextarea.postMountWrapper(inst);
}

function optionPostMount() {
  var inst = this;
  ReactDOMOption.postMountWrapper(inst);
}

var setAndValidateContentChildDev = emptyFunction;
if (true) {
  setAndValidateContentChildDev = function (content) {
    var hasExistingContent = this._contentDebugID != null;
    var debugID = this._debugID;
    // This ID represents the inlined child that has no backing instance:
    var contentDebugID = -debugID;

    if (content == null) {
      if (hasExistingContent) {
        ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID);
      }
      this._contentDebugID = null;
      return;
    }

    validateDOMNesting(null, String(content), this, this._ancestorInfo);
    this._contentDebugID = contentDebugID;
    if (hasExistingContent) {
      ReactInstrumentation.debugTool.onBeforeUpdateComponent(contentDebugID, content);
      ReactInstrumentation.debugTool.onUpdateComponent(contentDebugID);
    } else {
      ReactInstrumentation.debugTool.onBeforeMountComponent(contentDebugID, content, debugID);
      ReactInstrumentation.debugTool.onMountComponent(contentDebugID);
      ReactInstrumentation.debugTool.onSetChildren(debugID, [contentDebugID]);
    }
  };
}

// There are so many media events, it makes sense to just
// maintain a list rather than create a `trapBubbledEvent` for each
var mediaEvents = {
  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'
};

function trackInputValue() {
  inputValueTracking.track(this);
}

function trapBubbledEventsLocal() {
  var inst = this;
  // If a component renders to null or if another component fatals and causes
  // the state of the tree to be corrupted, `node` here can be null.
  !inst._rootNodeID ?  true ? invariant(false, 'Must be mounted to trap events') : _prodInvariant('63') : void 0;
  var node = getNode(inst);
  !node ?  true ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : _prodInvariant('64') : void 0;

  switch (inst._tag) {
    case 'iframe':
    case 'object':
      inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node)];
      break;
    case 'video':
    case 'audio':
      inst._wrapperState.listeners = [];
      // Create listener for each media event
      for (var event in mediaEvents) {
        if (mediaEvents.hasOwnProperty(event)) {
          inst._wrapperState.listeners.push(ReactBrowserEventEmitter.trapBubbledEvent(event, mediaEvents[event], node));
        }
      }
      break;
    case 'source':
      inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node)];
      break;
    case 'img':
      inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node), ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node)];
      break;
    case 'form':
      inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent('topReset', 'reset', node), ReactBrowserEventEmitter.trapBubbledEvent('topSubmit', 'submit', node)];
      break;
    case 'input':
    case 'select':
    case 'textarea':
      inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent('topInvalid', 'invalid', node)];
      break;
  }
}

function postUpdateSelectWrapper() {
  ReactDOMSelect.postUpdateWrapper(this);
}

// For HTML, certain tags should omit their close tag. We keep a whitelist for
// those special-case tags.

var omittedCloseTags = {
  area: true,
  base: true,
  br: true,
  col: true,
  embed: true,
  hr: true,
  img: true,
  input: true,
  keygen: true,
  link: true,
  meta: true,
  param: true,
  source: true,
  track: true,
  wbr: true
  // NOTE: menuitem's close tag should be omitted, but that causes problems.
};

var newlineEatingTags = {
  listing: true,
  pre: true,
  textarea: true
};

// For HTML, certain tags cannot have children. This has the same purpose as
// `omittedCloseTags` except that `menuitem` should still have its closing tag.

var voidElementTags = _assign({
  menuitem: true
}, omittedCloseTags);

// We accept any tag to be rendered but since this gets injected into arbitrary
// HTML, we want to make sure that it's a safe tag.
// http://www.w3.org/TR/REC-xml/#NT-Name

var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
var validatedTagCache = {};
var hasOwnProperty = {}.hasOwnProperty;

function validateDangerousTag(tag) {
  if (!hasOwnProperty.call(validatedTagCache, tag)) {
    !VALID_TAG_REGEX.test(tag) ?  true ? invariant(false, 'Invalid tag: %s', tag) : _prodInvariant('65', tag) : void 0;
    validatedTagCache[tag] = true;
  }
}

function isCustomComponent(tagName, props) {
  return tagName.indexOf('-') >= 0 || props.is != null;
}

var globalIdCounter = 1;

/**
 * Creates a new React class that is idempotent and capable of containing other
 * React components. It accepts event listeners and DOM properties that are
 * valid according to `DOMProperty`.
 *
 *  - Event listeners: `onClick`, `onMouseDown`, etc.
 *  - DOM properties: `className`, `name`, `title`, etc.
 *
 * The `style` property functions differently from the DOM API. It accepts an
 * object mapping of style properties to values.
 *
 * @constructor ReactDOMComponent
 * @extends ReactMultiChild
 */
function ReactDOMComponent(element) {
  var tag = element.type;
  validateDangerousTag(tag);
  this._currentElement = element;
  this._tag = tag.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;
  if (true) {
    this._ancestorInfo = null;
    setAndValidateContentChildDev.call(this, null);
  }
}

ReactDOMComponent.displayName = 'ReactDOMComponent';

ReactDOMComponent.Mixin = {
  /**
   * Generates root tag markup then recurses. This method has side effects and
   * is not idempotent.
   *
   * @internal
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {?ReactDOMComponent} the parent component instance
   * @param {?object} info about the host container
   * @param {object} context
   * @return {string} The computed markup.
   */
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    this._rootNodeID = globalIdCounter++;
    this._domID = hostContainerInfo._idCounter++;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    var props = 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
        };
        transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
        break;
      case 'input':
        ReactDOMInput.mountWrapper(this, props, hostParent);
        props = ReactDOMInput.getHostProps(this, props);
        transaction.getReactMountReady().enqueue(trackInputValue, this);
        transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
        break;
      case 'option':
        ReactDOMOption.mountWrapper(this, props, hostParent);
        props = ReactDOMOption.getHostProps(this, props);
        break;
      case 'select':
        ReactDOMSelect.mountWrapper(this, props, hostParent);
        props = ReactDOMSelect.getHostProps(this, props);
        transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
        break;
      case 'textarea':
        ReactDOMTextarea.mountWrapper(this, props, hostParent);
        props = ReactDOMTextarea.getHostProps(this, props);
        transaction.getReactMountReady().enqueue(trackInputValue, this);
        transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
        break;
    }

    assertValidProps(this, props);

    // We create tags in the namespace of their parent container, except HTML
    // tags get no namespace.
    var namespaceURI;
    var parentTag;
    if (hostParent != null) {
      namespaceURI = hostParent._namespaceURI;
      parentTag = hostParent._tag;
    } else if (hostContainerInfo._tag) {
      namespaceURI = hostContainerInfo._namespaceURI;
      parentTag = hostContainerInfo._tag;
    }
    if (namespaceURI == null || namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject') {
      namespaceURI = DOMNamespaces.html;
    }
    if (namespaceURI === DOMNamespaces.html) {
      if (this._tag === 'svg') {
        namespaceURI = DOMNamespaces.svg;
      } else if (this._tag === 'math') {
        namespaceURI = DOMNamespaces.mathml;
      }
    }
    this._namespaceURI = namespaceURI;

    if (true) {
      var parentInfo;
      if (hostParent != null) {
        parentInfo = hostParent._ancestorInfo;
      } else if (hostContainerInfo._tag) {
        parentInfo = hostContainerInfo._ancestorInfo;
      }
      if (parentInfo) {
        // parentInfo should always be present except for the top-level
        // component when server rendering
        validateDOMNesting(this._tag, null, this, parentInfo);
      }
      this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
    }

    var mountImage;
    if (transaction.useCreateElement) {
      var ownerDocument = hostContainerInfo._ownerDocument;
      var el;
      if (namespaceURI === DOMNamespaces.html) {
        if (this._tag === 'script') {
          // Create the script via .innerHTML so its "parser-inserted" flag is
          // set to true and it does not execute
          var div = ownerDocument.createElement('div');
          var type = this._currentElement.type;
          div.innerHTML = '<' + type + '></' + type + '>';
          el = div.removeChild(div.firstChild);
        } else if (props.is) {
          el = ownerDocument.createElement(this._currentElement.type, props.is);
        } else {
          // Separate else branch instead of using `props.is || undefined` above becuase of a Firefox bug.
          // See discussion in https://github.com/facebook/react/pull/6896
          // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240
          el = ownerDocument.createElement(this._currentElement.type);
        }
      } else {
        el = ownerDocument.createElementNS(namespaceURI, this._currentElement.type);
      }
      ReactDOMComponentTree.precacheNode(this, el);
      this._flags |= Flags.hasCachedChildNodes;
      if (!this._hostParent) {
        DOMPropertyOperations.setAttributeForRoot(el);
      }
      this._updateDOMProperties(null, props, transaction);
      var lazyTree = DOMLazyTree(el);
      this._createInitialChildren(transaction, props, context, lazyTree);
      mountImage = lazyTree;
    } else {
      var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
      var tagContent = this._createContentMarkup(transaction, props, context);
      if (!tagContent && omittedCloseTags[this._tag]) {
        mountImage = tagOpen + '/>';
      } else {
        mountImage = tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
      }
    }

    switch (this._tag) {
      case 'input':
        transaction.getReactMountReady().enqueue(inputPostMount, this);
        if (props.autoFocus) {
          transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
        }
        break;
      case 'textarea':
        transaction.getReactMountReady().enqueue(textareaPostMount, this);
        if (props.autoFocus) {
          transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
        }
        break;
      case 'select':
        if (props.autoFocus) {
          transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
        }
        break;
      case 'button':
        if (props.autoFocus) {
          transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
        }
        break;
      case 'option':
        transaction.getReactMountReady().enqueue(optionPostMount, this);
        break;
    }

    return mountImage;
  },

  /**
   * Creates markup for the open tag and all attributes.
   *
   * This method has side effects because events get registered.
   *
   * Iterating over object properties is faster than iterating over arrays.
   * @see http://jsperf.com/obj-vs-arr-iteration
   *
   * @private
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {object} props
   * @return {string} Markup of opening tag.
   */
  _createOpenTagMarkupAndPutListeners: function (transaction, props) {
    var ret = '<' + this._currentElement.type;

    for (var propKey in props) {
      if (!props.hasOwnProperty(propKey)) {
        continue;
      }
      var propValue = props[propKey];
      if (propValue == null) {
        continue;
      }
      if (registrationNameModules.hasOwnProperty(propKey)) {
        if (propValue) {
          enqueuePutListener(this, propKey, propValue, transaction);
        }
      } else {
        if (propKey === STYLE) {
          if (propValue) {
            if (true) {
              // See `_updateDOMProperties`. style block
              this._previousStyle = propValue;
            }
            propValue = this._previousStyleCopy = _assign({}, props.style);
          }
          propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this);
        }
        var markup = null;
        if (this._tag != null && isCustomComponent(this._tag, props)) {
          if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
            markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
          }
        } else {
          markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
        }
        if (markup) {
          ret += ' ' + markup;
        }
      }
    }

    // For static pages, no need to put React ID and checksum. Saves lots of
    // bytes.
    if (transaction.renderToStaticMarkup) {
      return ret;
    }

    if (!this._hostParent) {
      ret += ' ' + DOMPropertyOperations.createMarkupForRoot();
    }
    ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID);
    return ret;
  },

  /**
   * Creates markup for the content between the tags.
   *
   * @private
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {object} props
   * @param {object} context
   * @return {string} Content markup.
   */
  _createContentMarkup: function (transaction, props, context) {
    var ret = '';

    // Intentional use of != to avoid catching zero/false.
    var innerHTML = props.dangerouslySetInnerHTML;
    if (innerHTML != null) {
      if (innerHTML.__html != null) {
        ret = innerHTML.__html;
      }
    } else {
      var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
      var childrenToUse = contentToUse != null ? null : props.children;
      if (contentToUse != null) {
        // TODO: Validate that text is allowed as a child of this node
        ret = escapeTextContentForBrowser(contentToUse);
        if (true) {
          setAndValidateContentChildDev.call(this, contentToUse);
        }
      } else if (childrenToUse != null) {
        var mountImages = this.mountChildren(childrenToUse, transaction, context);
        ret = mountImages.join('');
      }
    }
    if (newlineEatingTags[this._tag] && ret.charAt(0) === '\n') {
      // text/html ignores the first character in these tags if it's a newline
      // Prefer to break application/xml over text/html (for now) by adding
      // a newline specifically to get eaten by the parser. (Alternately for
      // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first
      // \r is normalized out by HTMLTextAreaElement#value.)
      // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre>
      // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions>
      // See: <http://www.w3.org/TR/html5/syntax.html#newlines>
      // See: Parsing of "textarea" "listing" and "pre" elements
      //  from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody>
      return '\n' + ret;
    } else {
      return ret;
    }
  },

  _createInitialChildren: function (transaction, props, context, lazyTree) {
    // Intentional use of != to avoid catching zero/false.
    var innerHTML = props.dangerouslySetInnerHTML;
    if (innerHTML != null) {
      if (innerHTML.__html != null) {
        DOMLazyTree.queueHTML(lazyTree, innerHTML.__html);
      }
    } else {
      var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
      var childrenToUse = contentToUse != null ? null : props.children;
      // TODO: Validate that text is allowed as a child of this node
      if (contentToUse != null) {
        // Avoid setting textContent when the text is empty. In IE11 setting
        // textContent on a text area will cause the placeholder to not
        // show within the textarea until it has been focused and blurred again.
        // https://github.com/facebook/react/issues/6731#issuecomment-254874553
        if (contentToUse !== '') {
          if (true) {
            setAndValidateContentChildDev.call(this, contentToUse);
          }
          DOMLazyTree.queueText(lazyTree, contentToUse);
        }
      } else if (childrenToUse != null) {
        var mountImages = this.mountChildren(childrenToUse, transaction, context);
        for (var i = 0; i < mountImages.length; i++) {
          DOMLazyTree.queueChild(lazyTree, mountImages[i]);
        }
      }
    }
  },

  /**
   * Receives a next element and updates the component.
   *
   * @internal
   * @param {ReactElement} nextElement
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {object} context
   */
  receiveComponent: function (nextElement, transaction, context) {
    var prevElement = this._currentElement;
    this._currentElement = nextElement;
    this.updateComponent(transaction, prevElement, nextElement, context);
  },

  /**
   * Updates a DOM component after it has already been allocated and
   * attached to the DOM. Reconciles the root DOM node, then recurses.
   *
   * @param {ReactReconcileTransaction} transaction
   * @param {ReactElement} prevElement
   * @param {ReactElement} nextElement
   * @internal
   * @overridable
   */
  updateComponent: function (transaction, prevElement, nextElement, context) {
    var lastProps = prevElement.props;
    var nextProps = this._currentElement.props;

    switch (this._tag) {
      case 'input':
        lastProps = ReactDOMInput.getHostProps(this, lastProps);
        nextProps = ReactDOMInput.getHostProps(this, nextProps);
        break;
      case 'option':
        lastProps = ReactDOMOption.getHostProps(this, lastProps);
        nextProps = ReactDOMOption.getHostProps(this, nextProps);
        break;
      case 'select':
        lastProps = ReactDOMSelect.getHostProps(this, lastProps);
        nextProps = ReactDOMSelect.getHostProps(this, nextProps);
        break;
      case 'textarea':
        lastProps = ReactDOMTextarea.getHostProps(this, lastProps);
        nextProps = ReactDOMTextarea.getHostProps(this, nextProps);
        break;
    }

    assertValidProps(this, nextProps);
    this._updateDOMProperties(lastProps, nextProps, transaction);
    this._updateDOMChildren(lastProps, nextProps, transaction, context);

    switch (this._tag) {
      case 'input':
        // Update the wrapper around inputs *after* updating props. This has to
        // happen after `_updateDOMProperties`. Otherwise HTML5 input validations
        // raise warnings and prevent the new value from being assigned.
        ReactDOMInput.updateWrapper(this);

        // We also check that we haven't missed a value update, such as a
        // Radio group shifting the checked value to another named radio input.
        inputValueTracking.updateValueIfChanged(this);
        break;
      case 'textarea':
        ReactDOMTextarea.updateWrapper(this);
        break;
      case 'select':
        // <select> value update needs to occur after <option> children
        // reconciliation
        transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
        break;
    }
  },

  /**
   * Reconciles the properties by detecting differences in property values and
   * updating the DOM as necessary. This function is probably the single most
   * critical path for performance optimization.
   *
   * TODO: Benchmark whether checking for changed values in memory actually
   *       improves performance (especially statically positioned elements).
   * TODO: Benchmark the effects of putting this at the top since 99% of props
   *       do not change for a given reconciliation.
   * TODO: Benchmark areas that can be improved with caching.
   *
   * @private
   * @param {object} lastProps
   * @param {object} nextProps
   * @param {?DOMElement} node
   */
  _updateDOMProperties: function (lastProps, nextProps, transaction) {
    var propKey;
    var styleName;
    var styleUpdates;
    for (propKey in lastProps) {
      if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) {
        continue;
      }
      if (propKey === STYLE) {
        var lastStyle = this._previousStyleCopy;
        for (styleName in lastStyle) {
          if (lastStyle.hasOwnProperty(styleName)) {
            styleUpdates = styleUpdates || {};
            styleUpdates[styleName] = '';
          }
        }
        this._previousStyleCopy = null;
      } else if (registrationNameModules.hasOwnProperty(propKey)) {
        if (lastProps[propKey]) {
          // Only call deleteListener if there was a listener previously or
          // else willDeleteListener gets called when there wasn't actually a
          // listener (e.g., onClick={null})
          deleteListener(this, propKey);
        }
      } else if (isCustomComponent(this._tag, lastProps)) {
        if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
          DOMPropertyOperations.deleteValueForAttribute(getNode(this), propKey);
        }
      } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
        DOMPropertyOperations.deleteValueForProperty(getNode(this), propKey);
      }
    }
    for (propKey in nextProps) {
      var nextProp = nextProps[propKey];
      var lastProp = propKey === STYLE ? this._previousStyleCopy : lastProps != null ? lastProps[propKey] : undefined;
      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) {
        continue;
      }
      if (propKey === STYLE) {
        if (nextProp) {
          if (true) {
            checkAndWarnForMutatedStyle(this._previousStyleCopy, this._previousStyle, this);
            this._previousStyle = nextProp;
          }
          nextProp = this._previousStyleCopy = _assign({}, nextProp);
        } else {
          this._previousStyleCopy = null;
        }
        if (lastProp) {
          // Unset styles on `lastProp` but not on `nextProp`.
          for (styleName in lastProp) {
            if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) {
              styleUpdates = styleUpdates || {};
              styleUpdates[styleName] = '';
            }
          }
          // Update styles that changed since `lastProp`.
          for (styleName in nextProp) {
            if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) {
              styleUpdates = styleUpdates || {};
              styleUpdates[styleName] = nextProp[styleName];
            }
          }
        } else {
          // Relies on `updateStylesByID` not mutating `styleUpdates`.
          styleUpdates = nextProp;
        }
      } else if (registrationNameModules.hasOwnProperty(propKey)) {
        if (nextProp) {
          enqueuePutListener(this, propKey, nextProp, transaction);
        } else if (lastProp) {
          deleteListener(this, propKey);
        }
      } else if (isCustomComponent(this._tag, nextProps)) {
        if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
          DOMPropertyOperations.setValueForAttribute(getNode(this), propKey, nextProp);
        }
      } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
        var node = getNode(this);
        // If we're updating to null or undefined, we should remove the property
        // from the DOM node instead of inadvertently setting to a string. This
        // brings us in line with the same behavior we have on initial render.
        if (nextProp != null) {
          DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
        } else {
          DOMPropertyOperations.deleteValueForProperty(node, propKey);
        }
      }
    }
    if (styleUpdates) {
      CSSPropertyOperations.setValueForStyles(getNode(this), styleUpdates, this);
    }
  },

  /**
   * Reconciles the children with the various properties that affect the
   * children content.
   *
   * @param {object} lastProps
   * @param {object} nextProps
   * @param {ReactReconcileTransaction} transaction
   * @param {object} context
   */
  _updateDOMChildren: function (lastProps, nextProps, transaction, context) {
    var lastContent = CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
    var nextContent = CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;

    var lastHtml = lastProps.dangerouslySetInnerHTML && lastProps.dangerouslySetInnerHTML.__html;
    var nextHtml = nextProps.dangerouslySetInnerHTML && nextProps.dangerouslySetInnerHTML.__html;

    // Note the use of `!=` which checks for null or undefined.
    var lastChildren = lastContent != null ? null : lastProps.children;
    var nextChildren = nextContent != null ? null : nextProps.children;

    // If we're switching from children to content/html or vice versa, remove
    // the old content
    var lastHasContentOrHtml = lastContent != null || lastHtml != null;
    var nextHasContentOrHtml = nextContent != null || nextHtml != null;
    if (lastChildren != null && nextChildren == null) {
      this.updateChildren(null, transaction, context);
    } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
      this.updateTextContent('');
      if (true) {
        ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
      }
    }

    if (nextContent != null) {
      if (lastContent !== nextContent) {
        this.updateTextContent('' + nextContent);
        if (true) {
          setAndValidateContentChildDev.call(this, nextContent);
        }
      }
    } else if (nextHtml != null) {
      if (lastHtml !== nextHtml) {
        this.updateMarkup('' + nextHtml);
      }
      if (true) {
        ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
      }
    } else if (nextChildren != null) {
      if (true) {
        setAndValidateContentChildDev.call(this, null);
      }

      this.updateChildren(nextChildren, transaction, context);
    }
  },

  getHostNode: function () {
    return getNode(this);
  },

  /**
   * Destroys all event registrations for this instance. Does not remove from
   * the DOM. That must be done by the parent.
   *
   * @internal
   */
  unmountComponent: function (safely) {
    switch (this._tag) {
      case 'audio':
      case 'form':
      case 'iframe':
      case 'img':
      case 'link':
      case 'object':
      case 'source':
      case 'video':
        var listeners = this._wrapperState.listeners;
        if (listeners) {
          for (var i = 0; i < listeners.length; i++) {
            listeners[i].remove();
          }
        }
        break;
      case 'input':
      case 'textarea':
        inputValueTracking.stopTracking(this);
        break;
      case 'html':
      case 'head':
      case 'body':
        /**
         * Components like <html> <head> and <body> can't be removed or added
         * easily in a cross-browser way, however it's valuable to be able to
         * take advantage of React's reconciliation for styling and <title>
         * management. So we just document it and throw in dangerous cases.
         */
         true ?  true ? invariant(false, '<%s> tried to unmount. Because of cross-browser quirks it is impossible to unmount some top-level components (eg <html>, <head>, and <body>) reliably and efficiently. To fix this, have a single top-level component that never unmounts render these elements.', this._tag) : _prodInvariant('66', this._tag) : void 0;
        break;
    }

    this.unmountChildren(safely);
    ReactDOMComponentTree.uncacheNode(this);
    EventPluginHub.deleteAllListeners(this);
    this._rootNodeID = 0;
    this._domID = 0;
    this._wrapperState = null;

    if (true) {
      setAndValidateContentChildDev.call(this, null);
    }
  },

  getPublicInstance: function () {
    return getNode(this);
  }
};

_assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin);

module.exports = ReactDOMComponent;

/***/ }),
/* 130 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactDOMComponentTree = __webpack_require__(4);

var focusNode = __webpack_require__(69);

var AutoFocusUtils = {
  focusDOMComponent: function () {
    focusNode(ReactDOMComponentTree.getNodeFromInstance(this));
  }
};

module.exports = AutoFocusUtils;

/***/ }),
/* 131 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var CSSProperty = __webpack_require__(70);
var ExecutionEnvironment = __webpack_require__(5);
var ReactInstrumentation = __webpack_require__(7);

var camelizeStyleName = __webpack_require__(132);
var dangerousStyleValue = __webpack_require__(134);
var hyphenateStyleName = __webpack_require__(135);
var memoizeStringOnly = __webpack_require__(137);
var warning = __webpack_require__(1);

var processStyleName = memoizeStringOnly(function (styleName) {
  return hyphenateStyleName(styleName);
});

var hasShorthandPropertyBug = false;
var styleFloatAccessor = 'cssFloat';
if (ExecutionEnvironment.canUseDOM) {
  var tempStyle = document.createElement('div').style;
  try {
    // IE8 throws "Invalid argument." if resetting shorthand style properties.
    tempStyle.font = '';
  } catch (e) {
    hasShorthandPropertyBug = true;
  }
  // IE8 only supports accessing cssFloat (standard) as styleFloat
  if (document.documentElement.style.cssFloat === undefined) {
    styleFloatAccessor = 'styleFloat';
  }
}

if (true) {
  // 'msTransform' is correct, but the other prefixes should be capitalized
  var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;

  // style values shouldn't contain a semicolon
  var badStyleValueWithSemicolonPattern = /;\s*$/;

  var warnedStyleNames = {};
  var warnedStyleValues = {};
  var warnedForNaNValue = false;

  var warnHyphenatedStyleName = function (name, owner) {
    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
      return;
    }

    warnedStyleNames[name] = true;
     true ? warning(false, 'Unsupported style property %s. Did you mean %s?%s', name, camelizeStyleName(name), checkRenderMessage(owner)) : void 0;
  };

  var warnBadVendoredStyleName = function (name, owner) {
    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
      return;
    }

    warnedStyleNames[name] = true;
     true ? warning(false, 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', name, name.charAt(0).toUpperCase() + name.slice(1), checkRenderMessage(owner)) : void 0;
  };

  var warnStyleValueWithSemicolon = function (name, value, owner) {
    if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
      return;
    }

    warnedStyleValues[value] = true;
     true ? warning(false, "Style property values shouldn't contain a semicolon.%s " + 'Try "%s: %s" instead.', checkRenderMessage(owner), name, value.replace(badStyleValueWithSemicolonPattern, '')) : void 0;
  };

  var warnStyleValueIsNaN = function (name, value, owner) {
    if (warnedForNaNValue) {
      return;
    }

    warnedForNaNValue = true;
     true ? warning(false, '`NaN` is an invalid value for the `%s` css style property.%s', name, checkRenderMessage(owner)) : void 0;
  };

  var checkRenderMessage = function (owner) {
    if (owner) {
      var name = owner.getName();
      if (name) {
        return ' Check the render method of `' + name + '`.';
      }
    }
    return '';
  };

  /**
   * @param {string} name
   * @param {*} value
   * @param {ReactDOMComponent} component
   */
  var warnValidStyle = function (name, value, component) {
    var owner;
    if (component) {
      owner = component._currentElement._owner;
    }
    if (name.indexOf('-') > -1) {
      warnHyphenatedStyleName(name, owner);
    } else if (badVendoredStyleNamePattern.test(name)) {
      warnBadVendoredStyleName(name, owner);
    } else if (badStyleValueWithSemicolonPattern.test(value)) {
      warnStyleValueWithSemicolon(name, value, owner);
    }

    if (typeof value === 'number' && isNaN(value)) {
      warnStyleValueIsNaN(name, value, owner);
    }
  };
}

/**
 * Operations for dealing with CSS properties.
 */
var CSSPropertyOperations = {
  /**
   * Serializes a mapping of style properties for use as inline styles:
   *
   *   > createMarkupForStyles({width: '200px', height: 0})
   *   "width:200px;height:0;"
   *
   * Undefined values are ignored so that declarative programming is easier.
   * The result should be HTML-escaped before insertion into the DOM.
   *
   * @param {object} styles
   * @param {ReactDOMComponent} component
   * @return {?string}
   */
  createMarkupForStyles: function (styles, component) {
    var serialized = '';
    for (var styleName in styles) {
      if (!styles.hasOwnProperty(styleName)) {
        continue;
      }
      var isCustomProperty = styleName.indexOf('--') === 0;
      var styleValue = styles[styleName];
      if (true) {
        if (!isCustomProperty) {
          warnValidStyle(styleName, styleValue, component);
        }
      }
      if (styleValue != null) {
        serialized += processStyleName(styleName) + ':';
        serialized += dangerousStyleValue(styleName, styleValue, component, isCustomProperty) + ';';
      }
    }
    return serialized || null;
  },

  /**
   * Sets the value for multiple styles on a node.  If a value is specified as
   * '' (empty string), the corresponding style property will be unset.
   *
   * @param {DOMElement} node
   * @param {object} styles
   * @param {ReactDOMComponent} component
   */
  setValueForStyles: function (node, styles, component) {
    if (true) {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: component._debugID,
        type: 'update styles',
        payload: styles
      });
    }

    var style = node.style;
    for (var styleName in styles) {
      if (!styles.hasOwnProperty(styleName)) {
        continue;
      }
      var isCustomProperty = styleName.indexOf('--') === 0;
      if (true) {
        if (!isCustomProperty) {
          warnValidStyle(styleName, styles[styleName], component);
        }
      }
      var styleValue = dangerousStyleValue(styleName, styles[styleName], component, isCustomProperty);
      if (styleName === 'float' || styleName === 'cssFloat') {
        styleName = styleFloatAccessor;
      }
      if (isCustomProperty) {
        style.setProperty(styleName, styleValue);
      } else if (styleValue) {
        style[styleName] = styleValue;
      } else {
        var expansion = hasShorthandPropertyBug && CSSProperty.shorthandPropertyExpansions[styleName];
        if (expansion) {
          // Shorthand property that IE8 won't like unsetting, so unset each
          // component to placate it
          for (var individualStyleName in expansion) {
            style[individualStyleName] = '';
          }
        } else {
          style[styleName] = '';
        }
      }
    }
  }
};

module.exports = CSSPropertyOperations;

/***/ }),
/* 132 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */



var camelize = __webpack_require__(133);

var msPattern = /^-ms-/;

/**
 * Camelcases a hyphenated CSS property name, for example:
 *
 *   > camelizeStyleName('background-color')
 *   < "backgroundColor"
 *   > camelizeStyleName('-moz-transition')
 *   < "MozTransition"
 *   > camelizeStyleName('-ms-transition')
 *   < "msTransition"
 *
 * As Andi Smith suggests
 * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
 * is converted to lowercase `ms`.
 *
 * @param {string} string
 * @return {string}
 */
function camelizeStyleName(string) {
  return camelize(string.replace(msPattern, 'ms-'));
}

module.exports = camelizeStyleName;

/***/ }),
/* 133 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var _hyphenPattern = /-(.)/g;

/**
 * Camelcases a hyphenated string, for example:
 *
 *   > camelize('background-color')
 *   < "backgroundColor"
 *
 * @param {string} string
 * @return {string}
 */
function camelize(string) {
  return string.replace(_hyphenPattern, function (_, character) {
    return character.toUpperCase();
  });
}

module.exports = camelize;

/***/ }),
/* 134 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var CSSProperty = __webpack_require__(70);
var warning = __webpack_require__(1);

var isUnitlessNumber = CSSProperty.isUnitlessNumber;
var styleWarnings = {};

/**
 * Convert a value into the proper css writable value. The style name `name`
 * should be logical (no hyphens), as specified
 * in `CSSProperty.isUnitlessNumber`.
 *
 * @param {string} name CSS property name such as `topMargin`.
 * @param {*} value CSS property value such as `10px`.
 * @param {ReactDOMComponent} component
 * @return {string} Normalized style value with dimensions applied.
 */
function dangerousStyleValue(name, value, component, isCustomProperty) {
  // Note that we've removed escapeTextForBrowser() calls here since the
  // whole string will be escaped when the attribute is injected into
  // the markup. If you provide unsafe user data here they can inject
  // arbitrary CSS which may be problematic (I couldn't repro this):
  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
  // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
  // This is not an XSS hole but instead a potential CSS injection issue
  // which has lead to a greater discussion about how we're going to
  // trust URLs moving forward. See #2115901

  var isEmpty = value == null || typeof value === 'boolean' || value === '';
  if (isEmpty) {
    return '';
  }

  var isNonNumeric = isNaN(value);
  if (isCustomProperty || isNonNumeric || value === 0 || isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
    return '' + value; // cast to string
  }

  if (typeof value === 'string') {
    if (true) {
      // Allow '0' to pass through without warning. 0 is already special and
      // doesn't require units, so we don't need to warn about it.
      if (component && value !== '0') {
        var owner = component._currentElement._owner;
        var ownerName = owner ? owner.getName() : null;
        if (ownerName && !styleWarnings[ownerName]) {
          styleWarnings[ownerName] = {};
        }
        var warned = false;
        if (ownerName) {
          var warnings = styleWarnings[ownerName];
          warned = warnings[name];
          if (!warned) {
            warnings[name] = true;
          }
        }
        if (!warned) {
           true ? warning(false, 'a `%s` tag (owner: `%s`) was passed a numeric string value ' + 'for CSS property `%s` (value: `%s`) which will be treated ' + 'as a unitless number in a future version of React.', component._currentElement.type, ownerName || 'unknown', name, value) : void 0;
        }
      }
    }
    value = value.trim();
  }
  return value + 'px';
}

module.exports = dangerousStyleValue;

/***/ }),
/* 135 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */



var hyphenate = __webpack_require__(136);

var msPattern = /^ms-/;

/**
 * Hyphenates a camelcased CSS property name, for example:
 *
 *   > hyphenateStyleName('backgroundColor')
 *   < "background-color"
 *   > hyphenateStyleName('MozTransition')
 *   < "-moz-transition"
 *   > hyphenateStyleName('msTransition')
 *   < "-ms-transition"
 *
 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
 * is converted to `-ms-`.
 *
 * @param {string} string
 * @return {string}
 */
function hyphenateStyleName(string) {
  return hyphenate(string).replace(msPattern, '-ms-');
}

module.exports = hyphenateStyleName;

/***/ }),
/* 136 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var _uppercasePattern = /([A-Z])/g;

/**
 * Hyphenates a camelcased string, for example:
 *
 *   > hyphenate('backgroundColor')
 *   < "background-color"
 *
 * For CSS style names, use `hyphenateStyleName` instead which works properly
 * with all vendor prefixes, including `ms`.
 *
 * @param {string} string
 * @return {string}
 */
function hyphenate(string) {
  return string.replace(_uppercasePattern, '-$1').toLowerCase();
}

module.exports = hyphenate;

/***/ }),
/* 137 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 * @typechecks static-only
 */



/**
 * Memoizes the return value of a function that accepts one string argument.
 */

function memoizeStringOnly(callback) {
  var cache = {};
  return function (string) {
    if (!cache.hasOwnProperty(string)) {
      cache[string] = callback.call(this, string);
    }
    return cache[string];
  };
}

module.exports = memoizeStringOnly;

/***/ }),
/* 138 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var escapeTextContentForBrowser = __webpack_require__(32);

/**
 * Escapes attribute value to prevent scripting attacks.
 *
 * @param {*} value Value to escape.
 * @return {string} An escaped string.
 */
function quoteAttributeValueForBrowser(value) {
  return '"' + escapeTextContentForBrowser(value) + '"';
}

module.exports = quoteAttributeValueForBrowser;

/***/ }),
/* 139 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPluginHub = __webpack_require__(21);

function runEventQueueInBatch(events) {
  EventPluginHub.enqueueEvents(events);
  EventPluginHub.processEventQueue(false);
}

var ReactEventEmitterMixin = {
  /**
   * Streams a fired top-level event to `EventPluginHub` where plugins have the
   * opportunity to create `ReactEvent`s to be dispatched.
   */
  handleTopLevel: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    var events = EventPluginHub.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget);
    runEventQueueInBatch(events);
  }
};

module.exports = ReactEventEmitterMixin;

/***/ }),
/* 140 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);

/**
 * Generate a mapping of standard vendor prefixes using the defined style property and event name.
 *
 * @param {string} styleProp
 * @param {string} eventName
 * @returns {object}
 */
function makePrefixMap(styleProp, eventName) {
  var prefixes = {};

  prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();
  prefixes['Webkit' + styleProp] = 'webkit' + eventName;
  prefixes['Moz' + styleProp] = 'moz' + eventName;
  prefixes['ms' + styleProp] = 'MS' + eventName;
  prefixes['O' + styleProp] = 'o' + eventName.toLowerCase();

  return prefixes;
}

/**
 * A list of event names to a configurable list of vendor prefixes.
 */
var vendorPrefixes = {
  animationend: makePrefixMap('Animation', 'AnimationEnd'),
  animationiteration: makePrefixMap('Animation', 'AnimationIteration'),
  animationstart: makePrefixMap('Animation', 'AnimationStart'),
  transitionend: makePrefixMap('Transition', 'TransitionEnd')
};

/**
 * Event names that have already been detected and prefixed (if applicable).
 */
var prefixedEventNames = {};

/**
 * Element to check for prefixes on.
 */
var style = {};

/**
 * Bootstrap if a DOM exists.
 */
if (ExecutionEnvironment.canUseDOM) {
  style = document.createElement('div').style;

  // On some platforms, in particular some releases of Android 4.x,
  // the un-prefixed "animation" and "transition" properties are defined on the
  // style object but the events that fire will still be prefixed, so we need
  // to check if the un-prefixed events are usable, and if not remove them from the map.
  if (!('AnimationEvent' in window)) {
    delete vendorPrefixes.animationend.animation;
    delete vendorPrefixes.animationiteration.animation;
    delete vendorPrefixes.animationstart.animation;
  }

  // Same as above
  if (!('TransitionEvent' in window)) {
    delete vendorPrefixes.transitionend.transition;
  }
}

/**
 * Attempts to determine the correct vendor prefixed event name.
 *
 * @param {string} eventName
 * @returns {string}
 */
function getVendorPrefixedEventName(eventName) {
  if (prefixedEventNames[eventName]) {
    return prefixedEventNames[eventName];
  } else if (!vendorPrefixes[eventName]) {
    return eventName;
  }

  var prefixMap = vendorPrefixes[eventName];

  for (var styleProp in prefixMap) {
    if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
      return prefixedEventNames[eventName] = prefixMap[styleProp];
    }
  }

  return '';
}

module.exports = getVendorPrefixedEventName;

/***/ }),
/* 141 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var DOMPropertyOperations = __webpack_require__(71);
var LinkedValueUtils = __webpack_require__(44);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactUpdates = __webpack_require__(10);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

var didWarnValueLink = false;
var didWarnCheckedLink = false;
var didWarnValueDefaultValue = false;
var didWarnCheckedDefaultChecked = false;
var didWarnControlledToUncontrolled = false;
var didWarnUncontrolledToControlled = false;

function forceUpdateIfMounted() {
  if (this._rootNodeID) {
    // DOM component is still mounted; update
    ReactDOMInput.updateWrapper(this);
  }
}

function isControlled(props) {
  var usesChecked = props.type === 'checkbox' || props.type === 'radio';
  return usesChecked ? props.checked != null : props.value != null;
}

/**
 * Implements an <input> host component that allows setting these optional
 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
 *
 * If `checked` or `value` are not supplied (or null/undefined), user actions
 * that affect the checked state or value will trigger updates to the element.
 *
 * If they are supplied (and not null/undefined), the rendered element will not
 * trigger updates to the element. Instead, the props must change in order for
 * the rendered element to be updated.
 *
 * The rendered element will be initialized as unchecked (or `defaultChecked`)
 * with an empty value (or `defaultValue`).
 *
 * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
 */
var ReactDOMInput = {
  getHostProps: function (inst, props) {
    var value = LinkedValueUtils.getValue(props);
    var checked = LinkedValueUtils.getChecked(props);

    var hostProps = _assign({
      // Make sure we set .type before any other properties (setting .value
      // before .type means .value is lost in IE11 and below)
      type: undefined,
      // Make sure we set .step before .value (setting .value before .step
      // means .value is rounded on mount, based upon step precision)
      step: undefined,
      // Make sure we set .min & .max before .value (to ensure proper order
      // in corner cases such as min or max deriving from value, e.g. Issue #7170)
      min: undefined,
      max: undefined
    }, props, {
      defaultChecked: undefined,
      defaultValue: undefined,
      value: value != null ? value : inst._wrapperState.initialValue,
      checked: checked != null ? checked : inst._wrapperState.initialChecked,
      onChange: inst._wrapperState.onChange
    });

    return hostProps;
  },

  mountWrapper: function (inst, props) {
    if (true) {
      LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner);

      var owner = inst._currentElement._owner;

      if (props.valueLink !== undefined && !didWarnValueLink) {
         true ? warning(false, '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : void 0;
        didWarnValueLink = true;
      }
      if (props.checkedLink !== undefined && !didWarnCheckedLink) {
         true ? warning(false, '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : void 0;
        didWarnCheckedLink = true;
      }
      if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) {
         true ? warning(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0;
        didWarnCheckedDefaultChecked = true;
      }
      if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) {
         true ? warning(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0;
        didWarnValueDefaultValue = true;
      }
    }

    var defaultValue = props.defaultValue;
    inst._wrapperState = {
      initialChecked: props.checked != null ? props.checked : props.defaultChecked,
      initialValue: props.value != null ? props.value : defaultValue,
      listeners: null,
      onChange: _handleChange.bind(inst),
      controlled: isControlled(props)
    };
  },

  updateWrapper: function (inst) {
    var props = inst._currentElement.props;

    if (true) {
      var controlled = isControlled(props);
      var owner = inst._currentElement._owner;

      if (!inst._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) {
         true ? warning(false, '%s is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0;
        didWarnUncontrolledToControlled = true;
      }
      if (inst._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) {
         true ? warning(false, '%s is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0;
        didWarnControlledToUncontrolled = true;
      }
    }

    // TODO: Shouldn't this be getChecked(props)?
    var checked = props.checked;
    if (checked != null) {
      DOMPropertyOperations.setValueForProperty(ReactDOMComponentTree.getNodeFromInstance(inst), 'checked', checked || false);
    }

    var node = ReactDOMComponentTree.getNodeFromInstance(inst);
    var value = LinkedValueUtils.getValue(props);
    if (value != null) {
      if (value === 0 && node.value === '') {
        node.value = '0';
        // Note: IE9 reports a number inputs as 'text', so check props instead.
      } else if (props.type === 'number') {
        // Simulate `input.valueAsNumber`. IE9 does not support it
        var valueAsNumber = parseFloat(node.value, 10) || 0;

        if (
        // eslint-disable-next-line
        value != valueAsNumber ||
        // eslint-disable-next-line
        value == valueAsNumber && node.value != value) {
          // Cast `value` to a string to ensure the value is set correctly. While
          // browsers typically do this as necessary, jsdom doesn't.
          node.value = '' + value;
        }
      } else if (node.value !== '' + value) {
        // Cast `value` to a string to ensure the value is set correctly. While
        // browsers typically do this as necessary, jsdom doesn't.
        node.value = '' + value;
      }
    } else {
      if (props.value == null && props.defaultValue != null) {
        // In Chrome, assigning defaultValue to certain input types triggers input validation.
        // For number inputs, the display value loses trailing decimal points. For email inputs,
        // Chrome raises "The specified value <x> is not a valid email address".
        //
        // Here we check to see if the defaultValue has actually changed, avoiding these problems
        // when the user is inputting text
        //
        // https://github.com/facebook/react/issues/7253
        if (node.defaultValue !== '' + props.defaultValue) {
          node.defaultValue = '' + props.defaultValue;
        }
      }
      if (props.checked == null && props.defaultChecked != null) {
        node.defaultChecked = !!props.defaultChecked;
      }
    }
  },

  postMountWrapper: function (inst) {
    var props = inst._currentElement.props;

    // This is in postMount because we need access to the DOM node, which is not
    // available until after the component has mounted.
    var node = ReactDOMComponentTree.getNodeFromInstance(inst);

    // Detach value from defaultValue. We won't do anything if we're working on
    // submit or reset inputs as those values & defaultValues are linked. They
    // are not resetable nodes so this operation doesn't matter and actually
    // removes browser-default values (eg "Submit Query") when no value is
    // provided.

    switch (props.type) {
      case 'submit':
      case 'reset':
        break;
      case 'color':
      case 'date':
      case 'datetime':
      case 'datetime-local':
      case 'month':
      case 'time':
      case 'week':
        // This fixes the no-show issue on iOS Safari and Android Chrome:
        // https://github.com/facebook/react/issues/7233
        node.value = '';
        node.value = node.defaultValue;
        break;
      default:
        node.value = node.value;
        break;
    }

    // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug
    // this is needed to work around a chrome bug where setting defaultChecked
    // will sometimes influence the value of checked (even after detachment).
    // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416
    // We need to temporarily unset name to avoid disrupting radio button groups.
    var name = node.name;
    if (name !== '') {
      node.name = '';
    }
    node.defaultChecked = !node.defaultChecked;
    node.defaultChecked = !node.defaultChecked;
    if (name !== '') {
      node.name = name;
    }
  }
};

function _handleChange(event) {
  var props = this._currentElement.props;

  var returnValue = LinkedValueUtils.executeOnChange(props, event);

  // Here we use asap to wait until all updates have propagated, which
  // is important when using controlled components within layers:
  // https://github.com/facebook/react/issues/1698
  ReactUpdates.asap(forceUpdateIfMounted, this);

  var name = props.name;
  if (props.type === 'radio' && name != null) {
    var rootNode = ReactDOMComponentTree.getNodeFromInstance(this);
    var queryRoot = rootNode;

    while (queryRoot.parentNode) {
      queryRoot = queryRoot.parentNode;
    }

    // If `rootNode.form` was non-null, then we could try `form.elements`,
    // but that sometimes behaves strangely in IE8. We could also try using
    // `form.getElementsByName`, but that will only return direct children
    // and won't include inputs that use the HTML5 `form=` attribute. Since
    // the input might not even be in a form, let's just use the global
    // `querySelectorAll` to ensure we don't miss anything.
    var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]');

    for (var i = 0; i < group.length; i++) {
      var otherNode = group[i];
      if (otherNode === rootNode || otherNode.form !== rootNode.form) {
        continue;
      }
      // This will throw if radio buttons rendered by different copies of React
      // and the same name are rendered into the same form (same as #1939).
      // That's probably okay; we don't support it just as we don't support
      // mixing React radio buttons with non-React ones.
      var otherInstance = ReactDOMComponentTree.getInstanceFromNode(otherNode);
      !otherInstance ?  true ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.') : _prodInvariant('90') : void 0;
      // If this is a controlled radio button group, forcing the input that
      // was previously checked to update will cause it to be come re-checked
      // as appropriate.
      ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
    }
  }

  return returnValue;
}

module.exports = ReactDOMInput;

/***/ }),
/* 142 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var React = __webpack_require__(16);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactDOMSelect = __webpack_require__(73);

var warning = __webpack_require__(1);
var didWarnInvalidOptionChildren = false;

function flattenChildren(children) {
  var content = '';

  // Flatten children and warn if they aren't strings or numbers;
  // invalid types are ignored.
  React.Children.forEach(children, function (child) {
    if (child == null) {
      return;
    }
    if (typeof child === 'string' || typeof child === 'number') {
      content += child;
    } else if (!didWarnInvalidOptionChildren) {
      didWarnInvalidOptionChildren = true;
       true ? warning(false, 'Only strings and numbers are supported as <option> children.') : void 0;
    }
  });

  return content;
}

/**
 * Implements an <option> host component that warns when `selected` is set.
 */
var ReactDOMOption = {
  mountWrapper: function (inst, props, hostParent) {
    // TODO (yungsters): Remove support for `selected` in <option>.
    if (true) {
       true ? warning(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.') : void 0;
    }

    // Look up whether this option is 'selected'
    var selectValue = null;
    if (hostParent != null) {
      var selectParent = hostParent;

      if (selectParent._tag === 'optgroup') {
        selectParent = selectParent._hostParent;
      }

      if (selectParent != null && selectParent._tag === 'select') {
        selectValue = ReactDOMSelect.getSelectValueContext(selectParent);
      }
    }

    // If the value is null (e.g., no specified value or after initial mount)
    // or missing (e.g., for <datalist>), we don't change props.selected
    var selected = null;
    if (selectValue != null) {
      var value;
      if (props.value != null) {
        value = props.value + '';
      } else {
        value = flattenChildren(props.children);
      }
      selected = false;
      if (Array.isArray(selectValue)) {
        // multiple
        for (var i = 0; i < selectValue.length; i++) {
          if ('' + selectValue[i] === value) {
            selected = true;
            break;
          }
        }
      } else {
        selected = '' + selectValue === value;
      }
    }

    inst._wrapperState = { selected: selected };
  },

  postMountWrapper: function (inst) {
    // value="" should make a value attribute (#6219)
    var props = inst._currentElement.props;
    if (props.value != null) {
      var node = ReactDOMComponentTree.getNodeFromInstance(inst);
      node.setAttribute('value', props.value);
    }
  },

  getHostProps: function (inst, props) {
    var hostProps = _assign({ selected: undefined, children: undefined }, props);

    // Read state only from initial mount because <select> updates value
    // manually; we need the initial state only for server rendering
    if (inst._wrapperState.selected != null) {
      hostProps.selected = inst._wrapperState.selected;
    }

    var content = flattenChildren(props.children);

    if (content) {
      hostProps.children = content;
    }

    return hostProps;
  }
};

module.exports = ReactDOMOption;

/***/ }),
/* 143 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var LinkedValueUtils = __webpack_require__(44);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactUpdates = __webpack_require__(10);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

var didWarnValueLink = false;
var didWarnValDefaultVal = false;

function forceUpdateIfMounted() {
  if (this._rootNodeID) {
    // DOM component is still mounted; update
    ReactDOMTextarea.updateWrapper(this);
  }
}

/**
 * Implements a <textarea> host component that allows setting `value`, and
 * `defaultValue`. This differs from the traditional DOM API because value is
 * usually set as PCDATA children.
 *
 * If `value` is not supplied (or null/undefined), user actions that affect the
 * value will trigger updates to the element.
 *
 * If `value` is supplied (and not null/undefined), the rendered element will
 * not trigger updates to the element. Instead, the `value` prop must change in
 * order for the rendered element to be updated.
 *
 * The rendered element will be initialized with an empty value, the prop
 * `defaultValue` if specified, or the children content (deprecated).
 */
var ReactDOMTextarea = {
  getHostProps: function (inst, props) {
    !(props.dangerouslySetInnerHTML == null) ?  true ? invariant(false, '`dangerouslySetInnerHTML` does not make sense on <textarea>.') : _prodInvariant('91') : void 0;

    // Always set children to the same thing. In IE9, the selection range will
    // get reset if `textContent` is mutated.  We could add a check in setTextContent
    // to only set the value if/when the value differs from the node value (which would
    // completely solve this IE9 bug), but Sebastian+Ben seemed to like this solution.
    // The value can be a boolean or object so that's why it's forced to be a string.
    var hostProps = _assign({}, props, {
      value: undefined,
      defaultValue: undefined,
      children: '' + inst._wrapperState.initialValue,
      onChange: inst._wrapperState.onChange
    });

    return hostProps;
  },

  mountWrapper: function (inst, props) {
    if (true) {
      LinkedValueUtils.checkPropTypes('textarea', props, inst._currentElement._owner);
      if (props.valueLink !== undefined && !didWarnValueLink) {
         true ? warning(false, '`valueLink` prop on `textarea` is deprecated; set `value` and `onChange` instead.') : void 0;
        didWarnValueLink = true;
      }
      if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) {
         true ? warning(false, 'Textarea elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled textarea ' + 'and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0;
        didWarnValDefaultVal = true;
      }
    }

    var value = LinkedValueUtils.getValue(props);
    var initialValue = value;

    // Only bother fetching default value if we're going to use it
    if (value == null) {
      var defaultValue = props.defaultValue;
      // TODO (yungsters): Remove support for children content in <textarea>.
      var children = props.children;
      if (children != null) {
        if (true) {
           true ? warning(false, 'Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.') : void 0;
        }
        !(defaultValue == null) ?  true ? invariant(false, 'If you supply `defaultValue` on a <textarea>, do not pass children.') : _prodInvariant('92') : void 0;
        if (Array.isArray(children)) {
          !(children.length <= 1) ?  true ? invariant(false, '<textarea> can only have at most one child.') : _prodInvariant('93') : void 0;
          children = children[0];
        }

        defaultValue = '' + children;
      }
      if (defaultValue == null) {
        defaultValue = '';
      }
      initialValue = defaultValue;
    }

    inst._wrapperState = {
      initialValue: '' + initialValue,
      listeners: null,
      onChange: _handleChange.bind(inst)
    };
  },

  updateWrapper: function (inst) {
    var props = inst._currentElement.props;

    var node = ReactDOMComponentTree.getNodeFromInstance(inst);
    var value = LinkedValueUtils.getValue(props);
    if (value != null) {
      // Cast `value` to a string to ensure the value is set correctly. While
      // browsers typically do this as necessary, jsdom doesn't.
      var newValue = '' + value;

      // To avoid side effects (such as losing text selection), only set value if changed
      if (newValue !== node.value) {
        node.value = newValue;
      }
      if (props.defaultValue == null) {
        node.defaultValue = newValue;
      }
    }
    if (props.defaultValue != null) {
      node.defaultValue = props.defaultValue;
    }
  },

  postMountWrapper: function (inst) {
    // This is in postMount because we need access to the DOM node, which is not
    // available until after the component has mounted.
    var node = ReactDOMComponentTree.getNodeFromInstance(inst);
    var textContent = node.textContent;

    // Only set node.value if textContent is equal to the expected
    // initial value. In IE10/IE11 there is a bug where the placeholder attribute
    // will populate textContent as well.
    // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/
    if (textContent === inst._wrapperState.initialValue) {
      node.value = textContent;
    }
  }
};

function _handleChange(event) {
  var props = this._currentElement.props;
  var returnValue = LinkedValueUtils.executeOnChange(props, event);
  ReactUpdates.asap(forceUpdateIfMounted, this);
  return returnValue;
}

module.exports = ReactDOMTextarea;

/***/ }),
/* 144 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactComponentEnvironment = __webpack_require__(45);
var ReactInstanceMap = __webpack_require__(23);
var ReactInstrumentation = __webpack_require__(7);

var ReactCurrentOwner = __webpack_require__(9);
var ReactReconciler = __webpack_require__(18);
var ReactChildReconciler = __webpack_require__(145);

var emptyFunction = __webpack_require__(8);
var flattenChildren = __webpack_require__(152);
var invariant = __webpack_require__(0);

/**
 * Make an update for markup to be rendered and inserted at a supplied index.
 *
 * @param {string} markup Markup that renders into an element.
 * @param {number} toIndex Destination index.
 * @private
 */
function makeInsertMarkup(markup, afterNode, toIndex) {
  // NOTE: Null values reduce hidden classes.
  return {
    type: 'INSERT_MARKUP',
    content: markup,
    fromIndex: null,
    fromNode: null,
    toIndex: toIndex,
    afterNode: afterNode
  };
}

/**
 * Make an update for moving an existing element to another index.
 *
 * @param {number} fromIndex Source index of the existing element.
 * @param {number} toIndex Destination index of the element.
 * @private
 */
function makeMove(child, afterNode, toIndex) {
  // NOTE: Null values reduce hidden classes.
  return {
    type: 'MOVE_EXISTING',
    content: null,
    fromIndex: child._mountIndex,
    fromNode: ReactReconciler.getHostNode(child),
    toIndex: toIndex,
    afterNode: afterNode
  };
}

/**
 * Make an update for removing an element at an index.
 *
 * @param {number} fromIndex Index of the element to remove.
 * @private
 */
function makeRemove(child, node) {
  // NOTE: Null values reduce hidden classes.
  return {
    type: 'REMOVE_NODE',
    content: null,
    fromIndex: child._mountIndex,
    fromNode: node,
    toIndex: null,
    afterNode: null
  };
}

/**
 * Make an update for setting the markup of a node.
 *
 * @param {string} markup Markup that renders into an element.
 * @private
 */
function makeSetMarkup(markup) {
  // NOTE: Null values reduce hidden classes.
  return {
    type: 'SET_MARKUP',
    content: markup,
    fromIndex: null,
    fromNode: null,
    toIndex: null,
    afterNode: null
  };
}

/**
 * Make an update for setting the text content.
 *
 * @param {string} textContent Text content to set.
 * @private
 */
function makeTextContent(textContent) {
  // NOTE: Null values reduce hidden classes.
  return {
    type: 'TEXT_CONTENT',
    content: textContent,
    fromIndex: null,
    fromNode: null,
    toIndex: null,
    afterNode: null
  };
}

/**
 * Push an update, if any, onto the queue. Creates a new queue if none is
 * passed and always returns the queue. Mutative.
 */
function enqueue(queue, update) {
  if (update) {
    queue = queue || [];
    queue.push(update);
  }
  return queue;
}

/**
 * Processes any enqueued updates.
 *
 * @private
 */
function processQueue(inst, updateQueue) {
  ReactComponentEnvironment.processChildrenUpdates(inst, updateQueue);
}

var setChildrenForInstrumentation = emptyFunction;
if (true) {
  var getDebugID = function (inst) {
    if (!inst._debugID) {
      // Check for ART-like instances. TODO: This is silly/gross.
      var internal;
      if (internal = ReactInstanceMap.get(inst)) {
        inst = internal;
      }
    }
    return inst._debugID;
  };
  setChildrenForInstrumentation = function (children) {
    var debugID = getDebugID(this);
    // TODO: React Native empty components are also multichild.
    // This means they still get into this method but don't have _debugID.
    if (debugID !== 0) {
      ReactInstrumentation.debugTool.onSetChildren(debugID, children ? Object.keys(children).map(function (key) {
        return children[key]._debugID;
      }) : []);
    }
  };
}

/**
 * ReactMultiChild are capable of reconciling multiple children.
 *
 * @class ReactMultiChild
 * @internal
 */
var ReactMultiChild = {
  /**
   * Provides common functionality for components that must reconcile multiple
   * children. This is used by `ReactDOMComponent` to mount, update, and
   * unmount child components.
   *
   * @lends {ReactMultiChild.prototype}
   */
  Mixin: {
    _reconcilerInstantiateChildren: function (nestedChildren, transaction, context) {
      if (true) {
        var selfDebugID = getDebugID(this);
        if (this._currentElement) {
          try {
            ReactCurrentOwner.current = this._currentElement._owner;
            return ReactChildReconciler.instantiateChildren(nestedChildren, transaction, context, selfDebugID);
          } finally {
            ReactCurrentOwner.current = null;
          }
        }
      }
      return ReactChildReconciler.instantiateChildren(nestedChildren, transaction, context);
    },

    _reconcilerUpdateChildren: function (prevChildren, nextNestedChildrenElements, mountImages, removedNodes, transaction, context) {
      var nextChildren;
      var selfDebugID = 0;
      if (true) {
        selfDebugID = getDebugID(this);
        if (this._currentElement) {
          try {
            ReactCurrentOwner.current = this._currentElement._owner;
            nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID);
          } finally {
            ReactCurrentOwner.current = null;
          }
          ReactChildReconciler.updateChildren(prevChildren, nextChildren, mountImages, removedNodes, transaction, this, this._hostContainerInfo, context, selfDebugID);
          return nextChildren;
        }
      }
      nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID);
      ReactChildReconciler.updateChildren(prevChildren, nextChildren, mountImages, removedNodes, transaction, this, this._hostContainerInfo, context, selfDebugID);
      return nextChildren;
    },

    /**
     * Generates a "mount image" for each of the supplied children. In the case
     * of `ReactDOMComponent`, a mount image is a string of markup.
     *
     * @param {?object} nestedChildren Nested child maps.
     * @return {array} An array of mounted representations.
     * @internal
     */
    mountChildren: function (nestedChildren, transaction, context) {
      var children = this._reconcilerInstantiateChildren(nestedChildren, transaction, context);
      this._renderedChildren = children;

      var mountImages = [];
      var index = 0;
      for (var name in children) {
        if (children.hasOwnProperty(name)) {
          var child = children[name];
          var selfDebugID = 0;
          if (true) {
            selfDebugID = getDebugID(this);
          }
          var mountImage = ReactReconciler.mountComponent(child, transaction, this, this._hostContainerInfo, context, selfDebugID);
          child._mountIndex = index++;
          mountImages.push(mountImage);
        }
      }

      if (true) {
        setChildrenForInstrumentation.call(this, children);
      }

      return mountImages;
    },

    /**
     * Replaces any rendered children with a text content string.
     *
     * @param {string} nextContent String of content.
     * @internal
     */
    updateTextContent: function (nextContent) {
      var prevChildren = this._renderedChildren;
      // Remove any rendered children.
      ReactChildReconciler.unmountChildren(prevChildren, false);
      for (var name in prevChildren) {
        if (prevChildren.hasOwnProperty(name)) {
           true ?  true ? invariant(false, 'updateTextContent called on non-empty component.') : _prodInvariant('118') : void 0;
        }
      }
      // Set new text content.
      var updates = [makeTextContent(nextContent)];
      processQueue(this, updates);
    },

    /**
     * Replaces any rendered children with a markup string.
     *
     * @param {string} nextMarkup String of markup.
     * @internal
     */
    updateMarkup: function (nextMarkup) {
      var prevChildren = this._renderedChildren;
      // Remove any rendered children.
      ReactChildReconciler.unmountChildren(prevChildren, false);
      for (var name in prevChildren) {
        if (prevChildren.hasOwnProperty(name)) {
           true ?  true ? invariant(false, 'updateTextContent called on non-empty component.') : _prodInvariant('118') : void 0;
        }
      }
      var updates = [makeSetMarkup(nextMarkup)];
      processQueue(this, updates);
    },

    /**
     * Updates the rendered children with new children.
     *
     * @param {?object} nextNestedChildrenElements Nested child element maps.
     * @param {ReactReconcileTransaction} transaction
     * @internal
     */
    updateChildren: function (nextNestedChildrenElements, transaction, context) {
      // Hook used by React ART
      this._updateChildren(nextNestedChildrenElements, transaction, context);
    },

    /**
     * @param {?object} nextNestedChildrenElements Nested child element maps.
     * @param {ReactReconcileTransaction} transaction
     * @final
     * @protected
     */
    _updateChildren: function (nextNestedChildrenElements, transaction, context) {
      var prevChildren = this._renderedChildren;
      var removedNodes = {};
      var mountImages = [];
      var nextChildren = this._reconcilerUpdateChildren(prevChildren, nextNestedChildrenElements, mountImages, removedNodes, transaction, context);
      if (!nextChildren && !prevChildren) {
        return;
      }
      var updates = null;
      var name;
      // `nextIndex` will increment for each child in `nextChildren`, but
      // `lastIndex` will be the last index visited in `prevChildren`.
      var nextIndex = 0;
      var lastIndex = 0;
      // `nextMountIndex` will increment for each newly mounted child.
      var nextMountIndex = 0;
      var lastPlacedNode = null;
      for (name in nextChildren) {
        if (!nextChildren.hasOwnProperty(name)) {
          continue;
        }
        var prevChild = prevChildren && prevChildren[name];
        var nextChild = nextChildren[name];
        if (prevChild === nextChild) {
          updates = enqueue(updates, this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex));
          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
          prevChild._mountIndex = nextIndex;
        } else {
          if (prevChild) {
            // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
            lastIndex = Math.max(prevChild._mountIndex, lastIndex);
            // The `removedNodes` loop below will actually remove the child.
          }
          // The child must be instantiated before it's mounted.
          updates = enqueue(updates, this._mountChildAtIndex(nextChild, mountImages[nextMountIndex], lastPlacedNode, nextIndex, transaction, context));
          nextMountIndex++;
        }
        nextIndex++;
        lastPlacedNode = ReactReconciler.getHostNode(nextChild);
      }
      // Remove children that are no longer present.
      for (name in removedNodes) {
        if (removedNodes.hasOwnProperty(name)) {
          updates = enqueue(updates, this._unmountChild(prevChildren[name], removedNodes[name]));
        }
      }
      if (updates) {
        processQueue(this, updates);
      }
      this._renderedChildren = nextChildren;

      if (true) {
        setChildrenForInstrumentation.call(this, nextChildren);
      }
    },

    /**
     * Unmounts all rendered children. This should be used to clean up children
     * when this component is unmounted. It does not actually perform any
     * backend operations.
     *
     * @internal
     */
    unmountChildren: function (safely) {
      var renderedChildren = this._renderedChildren;
      ReactChildReconciler.unmountChildren(renderedChildren, safely);
      this._renderedChildren = null;
    },

    /**
     * Moves a child component to the supplied index.
     *
     * @param {ReactComponent} child Component to move.
     * @param {number} toIndex Destination index of the element.
     * @param {number} lastIndex Last index visited of the siblings of `child`.
     * @protected
     */
    moveChild: function (child, afterNode, toIndex, lastIndex) {
      // If the index of `child` is less than `lastIndex`, then it needs to
      // be moved. Otherwise, we do not need to move it because a child will be
      // inserted or moved before `child`.
      if (child._mountIndex < lastIndex) {
        return makeMove(child, afterNode, toIndex);
      }
    },

    /**
     * Creates a child component.
     *
     * @param {ReactComponent} child Component to create.
     * @param {string} mountImage Markup to insert.
     * @protected
     */
    createChild: function (child, afterNode, mountImage) {
      return makeInsertMarkup(mountImage, afterNode, child._mountIndex);
    },

    /**
     * Removes a child component.
     *
     * @param {ReactComponent} child Child to remove.
     * @protected
     */
    removeChild: function (child, node) {
      return makeRemove(child, node);
    },

    /**
     * Mounts a child with the supplied name.
     *
     * NOTE: This is part of `updateChildren` and is here for readability.
     *
     * @param {ReactComponent} child Component to mount.
     * @param {string} name Name of the child.
     * @param {number} index Index at which to insert the child.
     * @param {ReactReconcileTransaction} transaction
     * @private
     */
    _mountChildAtIndex: function (child, mountImage, afterNode, index, transaction, context) {
      child._mountIndex = index;
      return this.createChild(child, afterNode, mountImage);
    },

    /**
     * Unmounts a rendered child.
     *
     * NOTE: This is part of `updateChildren` and is here for readability.
     *
     * @param {ReactComponent} child Component to unmount.
     * @private
     */
    _unmountChild: function (child, node) {
      var update = this.removeChild(child, node);
      child._mountIndex = null;
      return update;
    }
  }
};

module.exports = ReactMultiChild;

/***/ }),
/* 145 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(process) {/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactReconciler = __webpack_require__(18);

var instantiateReactComponent = __webpack_require__(74);
var KeyEscapeUtils = __webpack_require__(48);
var shouldUpdateReactComponent = __webpack_require__(47);
var traverseAllChildren = __webpack_require__(78);
var warning = __webpack_require__(1);

var ReactComponentTreeHook;

if (typeof process !== 'undefined' && process.env && "test" === 'test') {
  // Temporary hack.
  // Inline requires don't work well with Jest:
  // https://github.com/facebook/react/issues/7240
  // Remove the inline requires when we don't need them anymore:
  // https://github.com/facebook/react/pull/7178
  ReactComponentTreeHook = __webpack_require__(6);
}

function instantiateChild(childInstances, child, name, selfDebugID) {
  // We found a component instance.
  var keyUnique = childInstances[name] === undefined;
  if (true) {
    if (!ReactComponentTreeHook) {
      ReactComponentTreeHook = __webpack_require__(6);
    }
    if (!keyUnique) {
       true ? warning(false, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), ReactComponentTreeHook.getStackAddendumByID(selfDebugID)) : void 0;
    }
  }
  if (child != null && keyUnique) {
    childInstances[name] = instantiateReactComponent(child, true);
  }
}

/**
 * ReactChildReconciler provides helpers for initializing or updating a set of
 * children. Its output is suitable for passing it onto ReactMultiChild which
 * does diffed reordering and insertion.
 */
var ReactChildReconciler = {
  /**
   * Generates a "mount image" for each of the supplied children. In the case
   * of `ReactDOMComponent`, a mount image is a string of markup.
   *
   * @param {?object} nestedChildNodes Nested child maps.
   * @return {?object} A set of child instances.
   * @internal
   */
  instantiateChildren: function (nestedChildNodes, transaction, context, selfDebugID) // 0 in production and for roots
  {
    if (nestedChildNodes == null) {
      return null;
    }
    var childInstances = {};

    if (true) {
      traverseAllChildren(nestedChildNodes, function (childInsts, child, name) {
        return instantiateChild(childInsts, child, name, selfDebugID);
      }, childInstances);
    } else {
      traverseAllChildren(nestedChildNodes, instantiateChild, childInstances);
    }
    return childInstances;
  },

  /**
   * Updates the rendered children and returns a new set of children.
   *
   * @param {?object} prevChildren Previously initialized set of children.
   * @param {?object} nextChildren Flat child element maps.
   * @param {ReactReconcileTransaction} transaction
   * @param {object} context
   * @return {?object} A new set of child instances.
   * @internal
   */
  updateChildren: function (prevChildren, nextChildren, mountImages, removedNodes, transaction, hostParent, hostContainerInfo, context, selfDebugID) // 0 in production and for roots
  {
    // We currently don't have a way to track moves here but if we use iterators
    // instead of for..in we can zip the iterators and check if an item has
    // moved.
    // TODO: If nothing has changed, return the prevChildren object so that we
    // can quickly bailout if nothing has changed.
    if (!nextChildren && !prevChildren) {
      return;
    }
    var name;
    var prevChild;
    for (name in nextChildren) {
      if (!nextChildren.hasOwnProperty(name)) {
        continue;
      }
      prevChild = prevChildren && prevChildren[name];
      var prevElement = prevChild && prevChild._currentElement;
      var nextElement = nextChildren[name];
      if (prevChild != null && shouldUpdateReactComponent(prevElement, nextElement)) {
        ReactReconciler.receiveComponent(prevChild, nextElement, transaction, context);
        nextChildren[name] = prevChild;
      } else {
        if (prevChild) {
          removedNodes[name] = ReactReconciler.getHostNode(prevChild);
          ReactReconciler.unmountComponent(prevChild, false);
        }
        // The child must be instantiated before it's mounted.
        var nextChildInstance = instantiateReactComponent(nextElement, true);
        nextChildren[name] = nextChildInstance;
        // Creating mount image now ensures refs are resolved in right order
        // (see https://github.com/facebook/react/pull/7101 for explanation).
        var nextChildMountImage = ReactReconciler.mountComponent(nextChildInstance, transaction, hostParent, hostContainerInfo, context, selfDebugID);
        mountImages.push(nextChildMountImage);
      }
    }
    // Unmount children that are no longer present.
    for (name in prevChildren) {
      if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) {
        prevChild = prevChildren[name];
        removedNodes[name] = ReactReconciler.getHostNode(prevChild);
        ReactReconciler.unmountComponent(prevChild, false);
      }
    }
  },

  /**
   * Unmounts all rendered children. This should be used to clean up children
   * when this component is unmounted.
   *
   * @param {?object} renderedChildren Previously initialized set of children.
   * @internal
   */
  unmountChildren: function (renderedChildren, safely) {
    for (var name in renderedChildren) {
      if (renderedChildren.hasOwnProperty(name)) {
        var renderedChild = renderedChildren[name];
        ReactReconciler.unmountComponent(renderedChild, safely);
      }
    }
  }
};

module.exports = ReactChildReconciler;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)))

/***/ }),
/* 146 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var React = __webpack_require__(16);
var ReactComponentEnvironment = __webpack_require__(45);
var ReactCurrentOwner = __webpack_require__(9);
var ReactErrorUtils = __webpack_require__(37);
var ReactInstanceMap = __webpack_require__(23);
var ReactInstrumentation = __webpack_require__(7);
var ReactNodeTypes = __webpack_require__(75);
var ReactReconciler = __webpack_require__(18);

if (true) {
  var checkReactTypeSpec = __webpack_require__(147);
}

var emptyObject = __webpack_require__(27);
var invariant = __webpack_require__(0);
var shallowEqual = __webpack_require__(46);
var shouldUpdateReactComponent = __webpack_require__(47);
var warning = __webpack_require__(1);

var CompositeTypes = {
  ImpureClass: 0,
  PureClass: 1,
  StatelessFunctional: 2
};

function StatelessComponent(Component) {}
StatelessComponent.prototype.render = function () {
  var Component = ReactInstanceMap.get(this)._currentElement.type;
  var element = Component(this.props, this.context, this.updater);
  warnIfInvalidElement(Component, element);
  return element;
};

function warnIfInvalidElement(Component, element) {
  if (true) {
     true ? warning(element === null || element === false || React.isValidElement(element), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component') : void 0;
     true ? warning(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component') : void 0;
  }
}

function shouldConstruct(Component) {
  return !!(Component.prototype && Component.prototype.isReactComponent);
}

function isPureComponent(Component) {
  return !!(Component.prototype && Component.prototype.isPureReactComponent);
}

// Separated into a function to contain deoptimizations caused by try/finally.
function measureLifeCyclePerf(fn, debugID, timerType) {
  if (debugID === 0) {
    // Top-level wrappers (see ReactMount) and empty components (see
    // ReactDOMEmptyComponent) are invisible to hooks and devtools.
    // Both are implementation details that should go away in the future.
    return fn();
  }

  ReactInstrumentation.debugTool.onBeginLifeCycleTimer(debugID, timerType);
  try {
    return fn();
  } finally {
    ReactInstrumentation.debugTool.onEndLifeCycleTimer(debugID, timerType);
  }
}

/**
 * ------------------ The Life-Cycle of a Composite Component ------------------
 *
 * - constructor: Initialization of state. The instance is now retained.
 *   - componentWillMount
 *   - render
 *   - [children's constructors]
 *     - [children's componentWillMount and render]
 *     - [children's componentDidMount]
 *     - componentDidMount
 *
 *       Update Phases:
 *       - componentWillReceiveProps (only called if parent updated)
 *       - shouldComponentUpdate
 *         - componentWillUpdate
 *           - render
 *           - [children's constructors or receive props phases]
 *         - componentDidUpdate
 *
 *     - componentWillUnmount
 *     - [children's componentWillUnmount]
 *   - [children destroyed]
 * - (destroyed): The instance is now blank, released by React and ready for GC.
 *
 * -----------------------------------------------------------------------------
 */

/**
 * An incrementing ID assigned to each component when it is mounted. This is
 * used to enforce the order in which `ReactUpdates` updates dirty components.
 *
 * @private
 */
var nextMountID = 1;

/**
 * @lends {ReactCompositeComponent.prototype}
 */
var ReactCompositeComponent = {
  /**
   * Base constructor for all composite component.
   *
   * @param {ReactElement} element
   * @final
   * @internal
   */
  construct: function (element) {
    this._currentElement = element;
    this._rootNodeID = 0;
    this._compositeType = null;
    this._instance = null;
    this._hostParent = null;
    this._hostContainerInfo = null;

    // See ReactUpdateQueue
    this._updateBatchNumber = null;
    this._pendingElement = null;
    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;

    this._renderedNodeType = null;
    this._renderedComponent = null;
    this._context = null;
    this._mountOrder = 0;
    this._topLevelWrapper = null;

    // See ReactUpdates and ReactUpdateQueue.
    this._pendingCallbacks = null;

    // ComponentWillUnmount shall only be called once
    this._calledComponentWillUnmount = false;

    if (true) {
      this._warnedAboutRefsInRender = false;
    }
  },

  /**
   * Initializes the component, renders markup, and registers event listeners.
   *
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {?object} hostParent
   * @param {?object} hostContainerInfo
   * @param {?object} context
   * @return {?string} Rendered markup to be inserted into the DOM.
   * @final
   * @internal
   */
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    var _this = this;

    this._context = context;
    this._mountOrder = nextMountID++;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    var publicProps = this._currentElement.props;
    var publicContext = this._processContext(context);

    var Component = this._currentElement.type;

    var updateQueue = transaction.getUpdateQueue();

    // Initialize the public class
    var doConstruct = shouldConstruct(Component);
    var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue);
    var renderedElement;

    // Support functional components
    if (!doConstruct && (inst == null || inst.render == null)) {
      renderedElement = inst;
      warnIfInvalidElement(Component, renderedElement);
      !(inst === null || inst === false || React.isValidElement(inst)) ?  true ? invariant(false, '%s(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component') : _prodInvariant('105', Component.displayName || Component.name || 'Component') : void 0;
      inst = new StatelessComponent(Component);
      this._compositeType = CompositeTypes.StatelessFunctional;
    } else {
      if (isPureComponent(Component)) {
        this._compositeType = CompositeTypes.PureClass;
      } else {
        this._compositeType = CompositeTypes.ImpureClass;
      }
    }

    if (true) {
      // This will throw later in _renderValidatedComponent, but add an early
      // warning now to help debugging
      if (inst.render == null) {
         true ? warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', Component.displayName || Component.name || 'Component') : void 0;
      }

      var propsMutated = inst.props !== publicProps;
      var componentName = Component.displayName || Component.name || 'Component';

       true ? warning(inst.props === undefined || !propsMutated, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", componentName, componentName) : void 0;
    }

    // These should be set up in the constructor, but as a convenience for
    // simpler class abstractions, we set them up after the fact.
    inst.props = publicProps;
    inst.context = publicContext;
    inst.refs = emptyObject;
    inst.updater = updateQueue;

    this._instance = inst;

    // Store a reference from the instance back to the internal representation
    ReactInstanceMap.set(inst, this);

    if (true) {
      // Since plain JS classes are defined without any special initialization
      // logic, we can not catch common errors early. Therefore, we have to
      // catch them here, at initialization time, instead.
       true ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved || inst.state, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', this.getName() || 'a component') : void 0;
       true ? warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', this.getName() || 'a component') : void 0;
       true ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : void 0;
       true ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : void 0;
       true ? warning(typeof inst.componentShouldUpdate !== 'function', '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', this.getName() || 'A component') : void 0;
       true ? warning(typeof inst.componentDidUnmount !== 'function', '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', this.getName() || 'A component') : void 0;
       true ? warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', this.getName() || 'A component') : void 0;
    }

    var initialState = inst.state;
    if (initialState === undefined) {
      inst.state = initialState = null;
    }
    !(typeof initialState === 'object' && !Array.isArray(initialState)) ?  true ? invariant(false, '%s.state: must be set to an object or null', this.getName() || 'ReactCompositeComponent') : _prodInvariant('106', this.getName() || 'ReactCompositeComponent') : void 0;

    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;

    var markup;
    if (inst.unstable_handleError) {
      markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context);
    } else {
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    }

    if (inst.componentDidMount) {
      if (true) {
        transaction.getReactMountReady().enqueue(function () {
          measureLifeCyclePerf(function () {
            return inst.componentDidMount();
          }, _this._debugID, 'componentDidMount');
        });
      } else {
        transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
      }
    }

    return markup;
  },

  _constructComponent: function (doConstruct, publicProps, publicContext, updateQueue) {
    if ("test" !== 'production' && !doConstruct) {
      ReactCurrentOwner.current = this;
      try {
        return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
      } finally {
        ReactCurrentOwner.current = null;
      }
    } else {
      return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
    }
  },

  _constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, updateQueue) {
    var Component = this._currentElement.type;

    if (doConstruct) {
      if (true) {
        return measureLifeCyclePerf(function () {
          return new Component(publicProps, publicContext, updateQueue);
        }, this._debugID, 'ctor');
      } else {
        return new Component(publicProps, publicContext, updateQueue);
      }
    }

    // This can still be an instance in case of factory components
    // but we'll count this as time spent rendering as the more common case.
    if (true) {
      return measureLifeCyclePerf(function () {
        return Component(publicProps, publicContext, updateQueue);
      }, this._debugID, 'render');
    } else {
      return Component(publicProps, publicContext, updateQueue);
    }
  },

  performInitialMountWithErrorHandling: function (renderedElement, hostParent, hostContainerInfo, transaction, context) {
    var markup;
    var checkpoint = transaction.checkpoint();
    try {
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    } catch (e) {
      // Roll back to checkpoint, handle error (which may add items to the transaction), and take a new checkpoint
      transaction.rollback(checkpoint);
      this._instance.unstable_handleError(e);
      if (this._pendingStateQueue) {
        this._instance.state = this._processPendingState(this._instance.props, this._instance.context);
      }
      checkpoint = transaction.checkpoint();

      this._renderedComponent.unmountComponent(true);
      transaction.rollback(checkpoint);

      // Try again - we've informed the component about the error, so they can render an error message this time.
      // If this throws again, the error will bubble up (and can be caught by a higher error boundary).
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    }
    return markup;
  },

  performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) {
    var inst = this._instance;

    var debugID = 0;
    if (true) {
      debugID = this._debugID;
    }

    if (inst.componentWillMount) {
      if (true) {
        measureLifeCyclePerf(function () {
          return inst.componentWillMount();
        }, debugID, 'componentWillMount');
      } else {
        inst.componentWillMount();
      }
      // When mounting, calls to `setState` by `componentWillMount` will set
      // `this._pendingStateQueue` without triggering a re-render.
      if (this._pendingStateQueue) {
        inst.state = this._processPendingState(inst.props, inst.context);
      }
    }

    // If not a stateless component, we now render
    if (renderedElement === undefined) {
      renderedElement = this._renderValidatedComponent();
    }

    var nodeType = ReactNodeTypes.getType(renderedElement);
    this._renderedNodeType = nodeType;
    var child = this._instantiateReactComponent(renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
    );
    this._renderedComponent = child;

    var markup = ReactReconciler.mountComponent(child, transaction, hostParent, hostContainerInfo, this._processChildContext(context), debugID);

    if (true) {
      if (debugID !== 0) {
        var childDebugIDs = child._debugID !== 0 ? [child._debugID] : [];
        ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs);
      }
    }

    return markup;
  },

  getHostNode: function () {
    return ReactReconciler.getHostNode(this._renderedComponent);
  },

  /**
   * Releases any resources allocated by `mountComponent`.
   *
   * @final
   * @internal
   */
  unmountComponent: function (safely) {
    if (!this._renderedComponent) {
      return;
    }

    var inst = this._instance;

    if (inst.componentWillUnmount && !inst._calledComponentWillUnmount) {
      inst._calledComponentWillUnmount = true;

      if (safely) {
        var name = this.getName() + '.componentWillUnmount()';
        ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst));
      } else {
        if (true) {
          measureLifeCyclePerf(function () {
            return inst.componentWillUnmount();
          }, this._debugID, 'componentWillUnmount');
        } else {
          inst.componentWillUnmount();
        }
      }
    }

    if (this._renderedComponent) {
      ReactReconciler.unmountComponent(this._renderedComponent, safely);
      this._renderedNodeType = null;
      this._renderedComponent = null;
      this._instance = null;
    }

    // Reset pending fields
    // Even if this component is scheduled for another update in ReactUpdates,
    // it would still be ignored because these fields are reset.
    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;
    this._pendingCallbacks = null;
    this._pendingElement = null;

    // These fields do not really need to be reset since this object is no
    // longer accessible.
    this._context = null;
    this._rootNodeID = 0;
    this._topLevelWrapper = null;

    // Delete the reference from the instance to this internal representation
    // which allow the internals to be properly cleaned up even if the user
    // leaks a reference to the public instance.
    ReactInstanceMap.remove(inst);

    // Some existing components rely on inst.props even after they've been
    // destroyed (in event handlers).
    // TODO: inst.props = null;
    // TODO: inst.state = null;
    // TODO: inst.context = null;
  },

  /**
   * Filters the context object to only contain keys specified in
   * `contextTypes`
   *
   * @param {object} context
   * @return {?object}
   * @private
   */
  _maskContext: function (context) {
    var Component = this._currentElement.type;
    var contextTypes = Component.contextTypes;
    if (!contextTypes) {
      return emptyObject;
    }
    var maskedContext = {};
    for (var contextName in contextTypes) {
      maskedContext[contextName] = context[contextName];
    }
    return maskedContext;
  },

  /**
   * Filters the context object to only contain keys specified in
   * `contextTypes`, and asserts that they are valid.
   *
   * @param {object} context
   * @return {?object}
   * @private
   */
  _processContext: function (context) {
    var maskedContext = this._maskContext(context);
    if (true) {
      var Component = this._currentElement.type;
      if (Component.contextTypes) {
        this._checkContextTypes(Component.contextTypes, maskedContext, 'context');
      }
    }
    return maskedContext;
  },

  /**
   * @param {object} currentContext
   * @return {object}
   * @private
   */
  _processChildContext: function (currentContext) {
    var Component = this._currentElement.type;
    var inst = this._instance;
    var childContext;

    if (inst.getChildContext) {
      if (true) {
        ReactInstrumentation.debugTool.onBeginProcessingChildContext();
        try {
          childContext = inst.getChildContext();
        } finally {
          ReactInstrumentation.debugTool.onEndProcessingChildContext();
        }
      } else {
        childContext = inst.getChildContext();
      }
    }

    if (childContext) {
      !(typeof Component.childContextTypes === 'object') ?  true ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().', this.getName() || 'ReactCompositeComponent') : _prodInvariant('107', this.getName() || 'ReactCompositeComponent') : void 0;
      if (true) {
        this._checkContextTypes(Component.childContextTypes, childContext, 'child context');
      }
      for (var name in childContext) {
        !(name in Component.childContextTypes) ?  true ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : _prodInvariant('108', this.getName() || 'ReactCompositeComponent', name) : void 0;
      }
      return _assign({}, currentContext, childContext);
    }
    return currentContext;
  },

  /**
   * Assert that the context types are valid
   *
   * @param {object} typeSpecs Map of context field to a ReactPropType
   * @param {object} values Runtime values that need to be type-checked
   * @param {string} location e.g. "prop", "context", "child context"
   * @private
   */
  _checkContextTypes: function (typeSpecs, values, location) {
    if (true) {
      checkReactTypeSpec(typeSpecs, values, location, this.getName(), null, this._debugID);
    }
  },

  receiveComponent: function (nextElement, transaction, nextContext) {
    var prevElement = this._currentElement;
    var prevContext = this._context;

    this._pendingElement = null;

    this.updateComponent(transaction, prevElement, nextElement, prevContext, nextContext);
  },

  /**
   * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate`
   * is set, update the component.
   *
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  performUpdateIfNecessary: function (transaction) {
    if (this._pendingElement != null) {
      ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context);
    } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
      this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
    } else {
      this._updateBatchNumber = null;
    }
  },

  /**
   * Perform an update to a mounted component. The componentWillReceiveProps and
   * shouldComponentUpdate methods are called, then (assuming the update isn't
   * skipped) the remaining update lifecycle methods are called and the DOM
   * representation is updated.
   *
   * By default, this implements React's rendering and reconciliation algorithm.
   * Sophisticated clients may wish to override this.
   *
   * @param {ReactReconcileTransaction} transaction
   * @param {ReactElement} prevParentElement
   * @param {ReactElement} nextParentElement
   * @internal
   * @overridable
   */
  updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {
    var inst = this._instance;
    !(inst != null) ?  true ? invariant(false, 'Attempted to update component `%s` that has already been unmounted (or failed to mount).', this.getName() || 'ReactCompositeComponent') : _prodInvariant('136', this.getName() || 'ReactCompositeComponent') : void 0;

    var willReceive = false;
    var nextContext;

    // Determine if the context has changed or not
    if (this._context === nextUnmaskedContext) {
      nextContext = inst.context;
    } else {
      nextContext = this._processContext(nextUnmaskedContext);
      willReceive = true;
    }

    var prevProps = prevParentElement.props;
    var nextProps = nextParentElement.props;

    // Not a simple state update but a props update
    if (prevParentElement !== nextParentElement) {
      willReceive = true;
    }

    // An update here will schedule an update but immediately set
    // _pendingStateQueue which will ensure that any state updates gets
    // immediately reconciled instead of waiting for the next batch.
    if (willReceive && inst.componentWillReceiveProps) {
      if (true) {
        measureLifeCyclePerf(function () {
          return inst.componentWillReceiveProps(nextProps, nextContext);
        }, this._debugID, 'componentWillReceiveProps');
      } else {
        inst.componentWillReceiveProps(nextProps, nextContext);
      }
    }

    var nextState = this._processPendingState(nextProps, nextContext);
    var shouldUpdate = true;

    if (!this._pendingForceUpdate) {
      if (inst.shouldComponentUpdate) {
        if (true) {
          shouldUpdate = measureLifeCyclePerf(function () {
            return inst.shouldComponentUpdate(nextProps, nextState, nextContext);
          }, this._debugID, 'shouldComponentUpdate');
        } else {
          shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
        }
      } else {
        if (this._compositeType === CompositeTypes.PureClass) {
          shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
        }
      }
    }

    if (true) {
       true ? warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent') : void 0;
    }

    this._updateBatchNumber = null;
    if (shouldUpdate) {
      this._pendingForceUpdate = false;
      // Will set `this.props`, `this.state` and `this.context`.
      this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext);
    } else {
      // If it's determined that a component should not update, we still want
      // to set props and state but we shortcut the rest of the update.
      this._currentElement = nextParentElement;
      this._context = nextUnmaskedContext;
      inst.props = nextProps;
      inst.state = nextState;
      inst.context = nextContext;
    }
  },

  _processPendingState: function (props, context) {
    var inst = this._instance;
    var queue = this._pendingStateQueue;
    var replace = this._pendingReplaceState;
    this._pendingReplaceState = false;
    this._pendingStateQueue = null;

    if (!queue) {
      return inst.state;
    }

    if (replace && queue.length === 1) {
      return queue[0];
    }

    var nextState = _assign({}, replace ? queue[0] : inst.state);
    for (var i = replace ? 1 : 0; i < queue.length; i++) {
      var partial = queue[i];
      _assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial);
    }

    return nextState;
  },

  /**
   * Merges new props and state, notifies delegate methods of update and
   * performs update.
   *
   * @param {ReactElement} nextElement Next element
   * @param {object} nextProps Next public object to set as properties.
   * @param {?object} nextState Next object to set as state.
   * @param {?object} nextContext Next public object to set as context.
   * @param {ReactReconcileTransaction} transaction
   * @param {?object} unmaskedContext
   * @private
   */
  _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) {
    var _this2 = this;

    var inst = this._instance;

    var hasComponentDidUpdate = Boolean(inst.componentDidUpdate);
    var prevProps;
    var prevState;
    var prevContext;
    if (hasComponentDidUpdate) {
      prevProps = inst.props;
      prevState = inst.state;
      prevContext = inst.context;
    }

    if (inst.componentWillUpdate) {
      if (true) {
        measureLifeCyclePerf(function () {
          return inst.componentWillUpdate(nextProps, nextState, nextContext);
        }, this._debugID, 'componentWillUpdate');
      } else {
        inst.componentWillUpdate(nextProps, nextState, nextContext);
      }
    }

    this._currentElement = nextElement;
    this._context = unmaskedContext;
    inst.props = nextProps;
    inst.state = nextState;
    inst.context = nextContext;

    this._updateRenderedComponent(transaction, unmaskedContext);

    if (hasComponentDidUpdate) {
      if (true) {
        transaction.getReactMountReady().enqueue(function () {
          measureLifeCyclePerf(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), _this2._debugID, 'componentDidUpdate');
        });
      } else {
        transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst);
      }
    }
  },

  /**
   * Call the component's `render` method and update the DOM accordingly.
   *
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  _updateRenderedComponent: function (transaction, context) {
    var prevComponentInstance = this._renderedComponent;
    var prevRenderedElement = prevComponentInstance._currentElement;
    var nextRenderedElement = this._renderValidatedComponent();

    var debugID = 0;
    if (true) {
      debugID = this._debugID;
    }

    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
      ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context));
    } else {
      var oldHostNode = ReactReconciler.getHostNode(prevComponentInstance);
      ReactReconciler.unmountComponent(prevComponentInstance, false);

      var nodeType = ReactNodeTypes.getType(nextRenderedElement);
      this._renderedNodeType = nodeType;
      var child = this._instantiateReactComponent(nextRenderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
      );
      this._renderedComponent = child;

      var nextMarkup = ReactReconciler.mountComponent(child, transaction, this._hostParent, this._hostContainerInfo, this._processChildContext(context), debugID);

      if (true) {
        if (debugID !== 0) {
          var childDebugIDs = child._debugID !== 0 ? [child._debugID] : [];
          ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs);
        }
      }

      this._replaceNodeWithMarkup(oldHostNode, nextMarkup, prevComponentInstance);
    }
  },

  /**
   * Overridden in shallow rendering.
   *
   * @protected
   */
  _replaceNodeWithMarkup: function (oldHostNode, nextMarkup, prevInstance) {
    ReactComponentEnvironment.replaceNodeWithMarkup(oldHostNode, nextMarkup, prevInstance);
  },

  /**
   * @protected
   */
  _renderValidatedComponentWithoutOwnerOrContext: function () {
    var inst = this._instance;
    var renderedElement;

    if (true) {
      renderedElement = measureLifeCyclePerf(function () {
        return inst.render();
      }, this._debugID, 'render');
    } else {
      renderedElement = inst.render();
    }

    if (true) {
      // We allow auto-mocks to proceed as if they're returning null.
      if (renderedElement === undefined && inst.render._isMockFunction) {
        // This is probably bad practice. Consider warning here and
        // deprecating this convenience.
        renderedElement = null;
      }
    }

    return renderedElement;
  },

  /**
   * @private
   */
  _renderValidatedComponent: function () {
    var renderedElement;
    if (true) {
      ReactCurrentOwner.current = this;
      try {
        renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
      } finally {
        ReactCurrentOwner.current = null;
      }
    } else {
      renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
    }
    !(
    // TODO: An `isValidNode` function would probably be more appropriate
    renderedElement === null || renderedElement === false || React.isValidElement(renderedElement)) ?  true ? invariant(false, '%s.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.', this.getName() || 'ReactCompositeComponent') : _prodInvariant('109', this.getName() || 'ReactCompositeComponent') : void 0;

    return renderedElement;
  },

  /**
   * Lazily allocates the refs object and stores `component` as `ref`.
   *
   * @param {string} ref Reference name.
   * @param {component} component Component to store as `ref`.
   * @final
   * @private
   */
  attachRef: function (ref, component) {
    var inst = this.getPublicInstance();
    !(inst != null) ?  true ? invariant(false, 'Stateless function components cannot have refs.') : _prodInvariant('110') : void 0;
    var publicComponentInstance = component.getPublicInstance();
    if (true) {
      var componentName = component && component.getName ? component.getName() : 'a component';
       true ? warning(publicComponentInstance != null || component._compositeType !== CompositeTypes.StatelessFunctional, 'Stateless function components cannot be given refs ' + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.', ref, componentName, this.getName()) : void 0;
    }
    var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
    refs[ref] = publicComponentInstance;
  },

  /**
   * Detaches a reference name.
   *
   * @param {string} ref Name to dereference.
   * @final
   * @private
   */
  detachRef: function (ref) {
    var refs = this.getPublicInstance().refs;
    delete refs[ref];
  },

  /**
   * Get a text description of the component that can be used to identify it
   * in error messages.
   * @return {string} The name or null.
   * @internal
   */
  getName: function () {
    var type = this._currentElement.type;
    var constructor = this._instance && this._instance.constructor;
    return type.displayName || constructor && constructor.displayName || type.name || constructor && constructor.name || null;
  },

  /**
   * Get the publicly accessible representation of this component - i.e. what
   * is exposed by refs and returned by render. Can be null for stateless
   * components.
   *
   * @return {ReactComponent} the public component instance.
   * @internal
   */
  getPublicInstance: function () {
    var inst = this._instance;
    if (this._compositeType === CompositeTypes.StatelessFunctional) {
      return null;
    }
    return inst;
  },

  // Stub
  _instantiateReactComponent: null
};

module.exports = ReactCompositeComponent;

/***/ }),
/* 147 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(process) {/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactPropTypeLocationNames = __webpack_require__(148);
var ReactPropTypesSecret = __webpack_require__(72);

var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

var ReactComponentTreeHook;

if (typeof process !== 'undefined' && process.env && "test" === 'test') {
  // Temporary hack.
  // Inline requires don't work well with Jest:
  // https://github.com/facebook/react/issues/7240
  // Remove the inline requires when we don't need them anymore:
  // https://github.com/facebook/react/pull/7178
  ReactComponentTreeHook = __webpack_require__(6);
}

var loggedTypeFailures = {};

/**
 * Assert that the values match with the type specs.
 * Error messages are memorized and will only be shown once.
 *
 * @param {object} typeSpecs Map of name to a ReactPropType
 * @param {object} values Runtime values that need to be type-checked
 * @param {string} location e.g. "prop", "context", "child context"
 * @param {string} componentName Name of the component for error messages.
 * @param {?object} element The React element that is being type-checked
 * @param {?number} debugID The React component instance that is being type-checked
 * @private
 */
function checkReactTypeSpec(typeSpecs, values, location, componentName, element, debugID) {
  for (var typeSpecName in typeSpecs) {
    if (typeSpecs.hasOwnProperty(typeSpecName)) {
      var error;
      // Prop type validation may throw. In case they do, we don't want to
      // fail the render phase where it didn't fail before. So we log it.
      // After these have been cleaned up, we'll let them throw.
      try {
        // This is intentionally an invariant that gets caught. It's the same
        // behavior as without this statement except with a better message.
        !(typeof typeSpecs[typeSpecName] === 'function') ?  true ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : _prodInvariant('84', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName) : void 0;
        error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
      } catch (ex) {
        error = ex;
      }
       true ? warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', ReactPropTypeLocationNames[location], typeSpecName, typeof error) : void 0;
      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
        // Only monitor this failure once because there tends to be a lot of the
        // same error.
        loggedTypeFailures[error.message] = true;

        var componentStackInfo = '';

        if (true) {
          if (!ReactComponentTreeHook) {
            ReactComponentTreeHook = __webpack_require__(6);
          }
          if (debugID !== null) {
            componentStackInfo = ReactComponentTreeHook.getStackAddendumByID(debugID);
          } else if (element !== null) {
            componentStackInfo = ReactComponentTreeHook.getCurrentStackAddendum(element);
          }
        }

         true ? warning(false, 'Failed %s type: %s%s', location, error.message, componentStackInfo) : void 0;
      }
    }
  }
}

module.exports = checkReactTypeSpec;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)))

/***/ }),
/* 148 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var ReactPropTypeLocationNames = {};

if (true) {
  ReactPropTypeLocationNames = {
    prop: 'prop',
    context: 'context',
    childContext: 'child context'
  };
}

module.exports = ReactPropTypeLocationNames;

/***/ }),
/* 149 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var nextDebugID = 1;

function getNextDebugID() {
  return nextDebugID++;
}

module.exports = getNextDebugID;

/***/ }),
/* 150 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



// The Symbol used to tag the ReactElement type. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.

var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7;

module.exports = REACT_ELEMENT_TYPE;

/***/ }),
/* 151 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



/* global Symbol */

var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.

/**
 * Returns the iterator method function contained on the iterable object.
 *
 * Be sure to invoke the function with the iterable as context:
 *
 *     var iteratorFn = getIteratorFn(myIterable);
 *     if (iteratorFn) {
 *       var iterator = iteratorFn.call(myIterable);
 *       ...
 *     }
 *
 * @param {?object} maybeIterable
 * @return {?function}
 */
function getIteratorFn(maybeIterable) {
  var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
  if (typeof iteratorFn === 'function') {
    return iteratorFn;
  }
}

module.exports = getIteratorFn;

/***/ }),
/* 152 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(process) {/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var KeyEscapeUtils = __webpack_require__(48);
var traverseAllChildren = __webpack_require__(78);
var warning = __webpack_require__(1);

var ReactComponentTreeHook;

if (typeof process !== 'undefined' && process.env && "test" === 'test') {
  // Temporary hack.
  // Inline requires don't work well with Jest:
  // https://github.com/facebook/react/issues/7240
  // Remove the inline requires when we don't need them anymore:
  // https://github.com/facebook/react/pull/7178
  ReactComponentTreeHook = __webpack_require__(6);
}

/**
 * @param {function} traverseContext Context passed through traversal.
 * @param {?ReactComponent} child React child component.
 * @param {!string} name String name of key path to child.
 * @param {number=} selfDebugID Optional debugID of the current internal instance.
 */
function flattenSingleChildIntoContext(traverseContext, child, name, selfDebugID) {
  // We found a component instance.
  if (traverseContext && typeof traverseContext === 'object') {
    var result = traverseContext;
    var keyUnique = result[name] === undefined;
    if (true) {
      if (!ReactComponentTreeHook) {
        ReactComponentTreeHook = __webpack_require__(6);
      }
      if (!keyUnique) {
         true ? warning(false, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), ReactComponentTreeHook.getStackAddendumByID(selfDebugID)) : void 0;
      }
    }
    if (keyUnique && child != null) {
      result[name] = child;
    }
  }
}

/**
 * Flattens children that are typically specified as `props.children`. Any null
 * children will not be included in the resulting object.
 * @return {!object} flattened children keyed by name.
 */
function flattenChildren(children, selfDebugID) {
  if (children == null) {
    return children;
  }
  var result = {};

  if (true) {
    traverseAllChildren(children, function (traverseContext, child, name) {
      return flattenSingleChildIntoContext(traverseContext, child, name, selfDebugID);
    }, result);
  } else {
    traverseAllChildren(children, flattenSingleChildIntoContext, result);
  }
  return result;
}

module.exports = flattenChildren;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)))

/***/ }),
/* 153 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var PooledClass = __webpack_require__(15);
var Transaction = __webpack_require__(29);
var ReactInstrumentation = __webpack_require__(7);
var ReactServerUpdateQueue = __webpack_require__(154);

/**
 * Executed within the scope of the `Transaction` instance. Consider these as
 * being member methods, but with an implied ordering while being isolated from
 * each other.
 */
var TRANSACTION_WRAPPERS = [];

if (true) {
  TRANSACTION_WRAPPERS.push({
    initialize: ReactInstrumentation.debugTool.onBeginFlush,
    close: ReactInstrumentation.debugTool.onEndFlush
  });
}

var noopCallbackQueue = {
  enqueue: function () {}
};

/**
 * @class ReactServerRenderingTransaction
 * @param {boolean} renderToStaticMarkup
 */
function ReactServerRenderingTransaction(renderToStaticMarkup) {
  this.reinitializeTransaction();
  this.renderToStaticMarkup = renderToStaticMarkup;
  this.useCreateElement = false;
  this.updateQueue = new ReactServerUpdateQueue(this);
}

var Mixin = {
  /**
   * @see Transaction
   * @abstract
   * @final
   * @return {array} Empty list of operation wrap procedures.
   */
  getTransactionWrappers: function () {
    return TRANSACTION_WRAPPERS;
  },

  /**
   * @return {object} The queue to collect `onDOMReady` callbacks with.
   */
  getReactMountReady: function () {
    return noopCallbackQueue;
  },

  /**
   * @return {object} The queue to collect React async events.
   */
  getUpdateQueue: function () {
    return this.updateQueue;
  },

  /**
   * `PooledClass` looks for this, and will invoke this before allowing this
   * instance to be reused.
   */
  destructor: function () {},

  checkpoint: function () {},

  rollback: function () {}
};

_assign(ReactServerRenderingTransaction.prototype, Transaction, Mixin);

PooledClass.addPoolingTo(ReactServerRenderingTransaction);

module.exports = ReactServerRenderingTransaction;

/***/ }),
/* 154 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var ReactUpdateQueue = __webpack_require__(49);

var warning = __webpack_require__(1);

function warnNoop(publicInstance, callerName) {
  if (true) {
    var constructor = publicInstance.constructor;
     true ? warning(false, '%s(...): Can only update a mounting component. ' + 'This usually means you called %s() outside componentWillMount() on the server. ' + 'This is a no-op. Please check the code for the %s component.', callerName, callerName, constructor && (constructor.displayName || constructor.name) || 'ReactClass') : void 0;
  }
}

/**
 * This is the update queue used for server rendering.
 * It delegates to ReactUpdateQueue while server rendering is in progress and
 * switches to ReactNoopUpdateQueue after the transaction has completed.
 * @class ReactServerUpdateQueue
 * @param {Transaction} transaction
 */

var ReactServerUpdateQueue = function () {
  function ReactServerUpdateQueue(transaction) {
    _classCallCheck(this, ReactServerUpdateQueue);

    this.transaction = transaction;
  }

  /**
   * Checks whether or not this composite component is mounted.
   * @param {ReactClass} publicInstance The instance we want to test.
   * @return {boolean} True if mounted, false otherwise.
   * @protected
   * @final
   */


  ReactServerUpdateQueue.prototype.isMounted = function isMounted(publicInstance) {
    return false;
  };

  /**
   * Enqueue a callback that will be executed after all the pending updates
   * have processed.
   *
   * @param {ReactClass} publicInstance The instance to use as `this` context.
   * @param {?function} callback Called after state is updated.
   * @internal
   */


  ReactServerUpdateQueue.prototype.enqueueCallback = function enqueueCallback(publicInstance, callback, callerName) {
    if (this.transaction.isInTransaction()) {
      ReactUpdateQueue.enqueueCallback(publicInstance, callback, callerName);
    }
  };

  /**
   * Forces an update. This should only be invoked when it is known with
   * certainty that we are **not** in a DOM transaction.
   *
   * You may want to call this when you know that some deeper aspect of the
   * component's state has changed but `setState` was not called.
   *
   * This will not invoke `shouldComponentUpdate`, but it will invoke
   * `componentWillUpdate` and `componentDidUpdate`.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @internal
   */


  ReactServerUpdateQueue.prototype.enqueueForceUpdate = function enqueueForceUpdate(publicInstance) {
    if (this.transaction.isInTransaction()) {
      ReactUpdateQueue.enqueueForceUpdate(publicInstance);
    } else {
      warnNoop(publicInstance, 'forceUpdate');
    }
  };

  /**
   * Replaces all of the state. Always use this or `setState` to mutate state.
   * You should treat `this.state` as immutable.
   *
   * There is no guarantee that `this.state` will be immediately updated, so
   * accessing `this.state` after calling this method may return the old value.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object|function} completeState Next state.
   * @internal
   */


  ReactServerUpdateQueue.prototype.enqueueReplaceState = function enqueueReplaceState(publicInstance, completeState) {
    if (this.transaction.isInTransaction()) {
      ReactUpdateQueue.enqueueReplaceState(publicInstance, completeState);
    } else {
      warnNoop(publicInstance, 'replaceState');
    }
  };

  /**
   * Sets a subset of the state. This only exists because _pendingState is
   * internal. This provides a merging strategy that is not available to deep
   * properties which is confusing. TODO: Expose pendingState or don't use it
   * during the merge.
   *
   * @param {ReactClass} publicInstance The instance that should rerender.
   * @param {object|function} partialState Next partial state to be merged with state.
   * @internal
   */


  ReactServerUpdateQueue.prototype.enqueueSetState = function enqueueSetState(publicInstance, partialState) {
    if (this.transaction.isInTransaction()) {
      ReactUpdateQueue.enqueueSetState(publicInstance, partialState);
    } else {
      warnNoop(publicInstance, 'setState');
    }
  };

  return ReactServerUpdateQueue;
}();

module.exports = ReactServerUpdateQueue;

/***/ }),
/* 155 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var DOMLazyTree = __webpack_require__(19);
var ReactDOMComponentTree = __webpack_require__(4);

var ReactDOMEmptyComponent = function (instantiate) {
  // ReactCompositeComponent uses this:
  this._currentElement = null;
  // ReactDOMComponentTree uses these:
  this._hostNode = null;
  this._hostParent = null;
  this._hostContainerInfo = null;
  this._domID = 0;
};
_assign(ReactDOMEmptyComponent.prototype, {
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    var domID = hostContainerInfo._idCounter++;
    this._domID = domID;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    var nodeValue = ' react-empty: ' + this._domID + ' ';
    if (transaction.useCreateElement) {
      var ownerDocument = hostContainerInfo._ownerDocument;
      var node = ownerDocument.createComment(nodeValue);
      ReactDOMComponentTree.precacheNode(this, node);
      return DOMLazyTree(node);
    } else {
      if (transaction.renderToStaticMarkup) {
        // Normally we'd insert a comment node, but since this is a situation
        // where React won't take over (static pages), we can simply return
        // nothing.
        return '';
      }
      return '<!--' + nodeValue + '-->';
    }
  },
  receiveComponent: function () {},
  getHostNode: function () {
    return ReactDOMComponentTree.getNodeFromInstance(this);
  },
  unmountComponent: function () {
    ReactDOMComponentTree.uncacheNode(this);
  }
});

module.exports = ReactDOMEmptyComponent;

/***/ }),
/* 156 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var invariant = __webpack_require__(0);

/**
 * Return the lowest common ancestor of A and B, or null if they are in
 * different trees.
 */
function getLowestCommonAncestor(instA, instB) {
  !('_hostNode' in instA) ?  true ? invariant(false, 'getNodeFromInstance: Invalid argument.') : _prodInvariant('33') : void 0;
  !('_hostNode' in instB) ?  true ? invariant(false, 'getNodeFromInstance: Invalid argument.') : _prodInvariant('33') : void 0;

  var depthA = 0;
  for (var tempA = instA; tempA; tempA = tempA._hostParent) {
    depthA++;
  }
  var depthB = 0;
  for (var tempB = instB; tempB; tempB = tempB._hostParent) {
    depthB++;
  }

  // If A is deeper, crawl up.
  while (depthA - depthB > 0) {
    instA = instA._hostParent;
    depthA--;
  }

  // If B is deeper, crawl up.
  while (depthB - depthA > 0) {
    instB = instB._hostParent;
    depthB--;
  }

  // Walk in lockstep until we find a match.
  var depth = depthA;
  while (depth--) {
    if (instA === instB) {
      return instA;
    }
    instA = instA._hostParent;
    instB = instB._hostParent;
  }
  return null;
}

/**
 * Return if A is an ancestor of B.
 */
function isAncestor(instA, instB) {
  !('_hostNode' in instA) ?  true ? invariant(false, 'isAncestor: Invalid argument.') : _prodInvariant('35') : void 0;
  !('_hostNode' in instB) ?  true ? invariant(false, 'isAncestor: Invalid argument.') : _prodInvariant('35') : void 0;

  while (instB) {
    if (instB === instA) {
      return true;
    }
    instB = instB._hostParent;
  }
  return false;
}

/**
 * Return the parent instance of the passed-in instance.
 */
function getParentInstance(inst) {
  !('_hostNode' in inst) ?  true ? invariant(false, 'getParentInstance: Invalid argument.') : _prodInvariant('36') : void 0;

  return inst._hostParent;
}

/**
 * Simulates the traversal of a two-phase, capture/bubble event dispatch.
 */
function traverseTwoPhase(inst, fn, arg) {
  var path = [];
  while (inst) {
    path.push(inst);
    inst = inst._hostParent;
  }
  var i;
  for (i = path.length; i-- > 0;) {
    fn(path[i], 'captured', arg);
  }
  for (i = 0; i < path.length; i++) {
    fn(path[i], 'bubbled', arg);
  }
}

/**
 * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
 * should would receive a `mouseEnter` or `mouseLeave` event.
 *
 * Does not invoke the callback on the nearest common ancestor because nothing
 * "entered" or "left" that element.
 */
function traverseEnterLeave(from, to, fn, argFrom, argTo) {
  var common = from && to ? getLowestCommonAncestor(from, to) : null;
  var pathFrom = [];
  while (from && from !== common) {
    pathFrom.push(from);
    from = from._hostParent;
  }
  var pathTo = [];
  while (to && to !== common) {
    pathTo.push(to);
    to = to._hostParent;
  }
  var i;
  for (i = 0; i < pathFrom.length; i++) {
    fn(pathFrom[i], 'bubbled', argFrom);
  }
  for (i = pathTo.length; i-- > 0;) {
    fn(pathTo[i], 'captured', argTo);
  }
}

module.exports = {
  isAncestor: isAncestor,
  getLowestCommonAncestor: getLowestCommonAncestor,
  getParentInstance: getParentInstance,
  traverseTwoPhase: traverseTwoPhase,
  traverseEnterLeave: traverseEnterLeave
};

/***/ }),
/* 157 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2),
    _assign = __webpack_require__(3);

var DOMChildrenOperations = __webpack_require__(41);
var DOMLazyTree = __webpack_require__(19);
var ReactDOMComponentTree = __webpack_require__(4);

var escapeTextContentForBrowser = __webpack_require__(32);
var invariant = __webpack_require__(0);
var validateDOMNesting = __webpack_require__(50);

/**
 * Text nodes violate a couple assumptions that React makes about components:
 *
 *  - When mounting text into the DOM, adjacent text nodes are merged.
 *  - Text nodes cannot be assigned a React root ID.
 *
 * This component is used to wrap strings between comment nodes so that they
 * can undergo the same reconciliation that is applied to elements.
 *
 * TODO: Investigate representing React components in the DOM with text nodes.
 *
 * @class ReactDOMTextComponent
 * @extends ReactComponent
 * @internal
 */
var ReactDOMTextComponent = function (text) {
  // TODO: This is really a ReactText (ReactNode), not a ReactElement
  this._currentElement = text;
  this._stringText = '' + text;
  // ReactDOMComponentTree uses these:
  this._hostNode = null;
  this._hostParent = null;

  // Properties
  this._domID = 0;
  this._mountIndex = 0;
  this._closingComment = null;
  this._commentNodes = null;
};

_assign(ReactDOMTextComponent.prototype, {
  /**
   * Creates the markup for this text node. This node is not intended to have
   * any features besides containing text content.
   *
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @return {string} Markup for this text node.
   * @internal
   */
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    if (true) {
      var parentInfo;
      if (hostParent != null) {
        parentInfo = hostParent._ancestorInfo;
      } else if (hostContainerInfo != null) {
        parentInfo = hostContainerInfo._ancestorInfo;
      }
      if (parentInfo) {
        // parentInfo should always be present except for the top-level
        // component when server rendering
        validateDOMNesting(null, this._stringText, this, parentInfo);
      }
    }

    var domID = hostContainerInfo._idCounter++;
    var openingValue = ' react-text: ' + domID + ' ';
    var closingValue = ' /react-text ';
    this._domID = domID;
    this._hostParent = hostParent;
    if (transaction.useCreateElement) {
      var ownerDocument = hostContainerInfo._ownerDocument;
      var openingComment = ownerDocument.createComment(openingValue);
      var closingComment = ownerDocument.createComment(closingValue);
      var lazyTree = DOMLazyTree(ownerDocument.createDocumentFragment());
      DOMLazyTree.queueChild(lazyTree, DOMLazyTree(openingComment));
      if (this._stringText) {
        DOMLazyTree.queueChild(lazyTree, DOMLazyTree(ownerDocument.createTextNode(this._stringText)));
      }
      DOMLazyTree.queueChild(lazyTree, DOMLazyTree(closingComment));
      ReactDOMComponentTree.precacheNode(this, openingComment);
      this._closingComment = closingComment;
      return lazyTree;
    } else {
      var escapedText = escapeTextContentForBrowser(this._stringText);

      if (transaction.renderToStaticMarkup) {
        // Normally we'd wrap this between comment nodes for the reasons stated
        // above, but since this is a situation where React won't take over
        // (static pages), we can simply return the text as it is.
        return escapedText;
      }

      return '<!--' + openingValue + '-->' + escapedText + '<!--' + closingValue + '-->';
    }
  },

  /**
   * Updates this component by updating the text content.
   *
   * @param {ReactText} nextText The next text content
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  receiveComponent: function (nextText, transaction) {
    if (nextText !== this._currentElement) {
      this._currentElement = nextText;
      var nextStringText = '' + nextText;
      if (nextStringText !== this._stringText) {
        // TODO: Save this as pending props and use performUpdateIfNecessary
        // and/or updateComponent to do the actual update for consistency with
        // other component types?
        this._stringText = nextStringText;
        var commentNodes = this.getHostNode();
        DOMChildrenOperations.replaceDelimitedText(commentNodes[0], commentNodes[1], nextStringText);
      }
    }
  },

  getHostNode: function () {
    var hostNode = this._commentNodes;
    if (hostNode) {
      return hostNode;
    }
    if (!this._closingComment) {
      var openingComment = ReactDOMComponentTree.getNodeFromInstance(this);
      var node = openingComment.nextSibling;
      while (true) {
        !(node != null) ?  true ? invariant(false, 'Missing closing comment for text component %s', this._domID) : _prodInvariant('67', this._domID) : void 0;
        if (node.nodeType === 8 && node.nodeValue === ' /react-text ') {
          this._closingComment = node;
          break;
        }
        node = node.nextSibling;
      }
    }
    hostNode = [this._hostNode, this._closingComment];
    this._commentNodes = hostNode;
    return hostNode;
  },

  unmountComponent: function () {
    this._closingComment = null;
    this._commentNodes = null;
    ReactDOMComponentTree.uncacheNode(this);
  }
});

module.exports = ReactDOMTextComponent;

/***/ }),
/* 158 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var ReactUpdates = __webpack_require__(10);
var Transaction = __webpack_require__(29);

var emptyFunction = __webpack_require__(8);

var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function () {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  }
};

var FLUSH_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
};

var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];

function ReactDefaultBatchingStrategyTransaction() {
  this.reinitializeTransaction();
}

_assign(ReactDefaultBatchingStrategyTransaction.prototype, Transaction, {
  getTransactionWrappers: function () {
    return TRANSACTION_WRAPPERS;
  }
});

var transaction = new ReactDefaultBatchingStrategyTransaction();

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  /**
   * Call the provided function in a context within which calls to `setState`
   * and friends are batched such that components aren't updated unnecessarily.
   */
  batchedUpdates: function (callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    // The code is written this way to avoid extra allocations
    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  }
};

module.exports = ReactDefaultBatchingStrategy;

/***/ }),
/* 159 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var EventListener = __webpack_require__(79);
var ExecutionEnvironment = __webpack_require__(5);
var PooledClass = __webpack_require__(15);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactUpdates = __webpack_require__(10);

var getEventTarget = __webpack_require__(38);
var getUnboundedScrollPosition = __webpack_require__(160);

/**
 * Find the deepest React component completely containing the root of the
 * passed-in instance (for use when entire React trees are nested within each
 * other). If React trees are not nested, returns null.
 */
function findParent(inst) {
  // TODO: It may be a good idea to cache this to prevent unnecessary DOM
  // traversal, but caching is difficult to do correctly without using a
  // mutation observer to listen for all DOM changes.
  while (inst._hostParent) {
    inst = inst._hostParent;
  }
  var rootNode = ReactDOMComponentTree.getNodeFromInstance(inst);
  var container = rootNode.parentNode;
  return ReactDOMComponentTree.getClosestInstanceFromNode(container);
}

// Used to store ancestor hierarchy in top level callback
function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
  this.topLevelType = topLevelType;
  this.nativeEvent = nativeEvent;
  this.ancestors = [];
}
_assign(TopLevelCallbackBookKeeping.prototype, {
  destructor: function () {
    this.topLevelType = null;
    this.nativeEvent = null;
    this.ancestors.length = 0;
  }
});
PooledClass.addPoolingTo(TopLevelCallbackBookKeeping, PooledClass.twoArgumentPooler);

function handleTopLevelImpl(bookKeeping) {
  var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
  var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(nativeEventTarget);

  // Loop through the hierarchy, in case there's any nested components.
  // It's important that we build the array of ancestors before calling any
  // event handlers, because event handlers can modify the DOM, leading to
  // inconsistencies with ReactMount's node cache. See #1105.
  var ancestor = targetInst;
  do {
    bookKeeping.ancestors.push(ancestor);
    ancestor = ancestor && findParent(ancestor);
  } while (ancestor);

  for (var i = 0; i < bookKeeping.ancestors.length; i++) {
    targetInst = bookKeeping.ancestors[i];
    ReactEventListener._handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent));
  }
}

function scrollValueMonitor(cb) {
  var scrollPosition = getUnboundedScrollPosition(window);
  cb(scrollPosition);
}

var ReactEventListener = {
  _enabled: true,
  _handleTopLevel: null,

  WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,

  setHandleTopLevel: function (handleTopLevel) {
    ReactEventListener._handleTopLevel = handleTopLevel;
  },

  setEnabled: function (enabled) {
    ReactEventListener._enabled = !!enabled;
  },

  isEnabled: function () {
    return ReactEventListener._enabled;
  },

  /**
   * Traps top-level events by using event bubbling.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {string} handlerBaseName Event name (e.g. "click").
   * @param {object} element Element on which to attach listener.
   * @return {?object} An object with a remove function which will forcefully
   *                  remove the listener.
   * @internal
   */
  trapBubbledEvent: function (topLevelType, handlerBaseName, element) {
    if (!element) {
      return null;
    }
    return EventListener.listen(element, handlerBaseName, ReactEventListener.dispatchEvent.bind(null, topLevelType));
  },

  /**
   * Traps a top-level event by using event capturing.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {string} handlerBaseName Event name (e.g. "click").
   * @param {object} element Element on which to attach listener.
   * @return {?object} An object with a remove function which will forcefully
   *                  remove the listener.
   * @internal
   */
  trapCapturedEvent: function (topLevelType, handlerBaseName, element) {
    if (!element) {
      return null;
    }
    return EventListener.capture(element, handlerBaseName, ReactEventListener.dispatchEvent.bind(null, topLevelType));
  },

  monitorScrollValue: function (refresh) {
    var callback = scrollValueMonitor.bind(null, refresh);
    EventListener.listen(window, 'scroll', callback);
  },

  dispatchEvent: function (topLevelType, nativeEvent) {
    if (!ReactEventListener._enabled) {
      return;
    }

    var bookKeeping = TopLevelCallbackBookKeeping.getPooled(topLevelType, nativeEvent);
    try {
      // Event queue being processed in the same cycle allows
      // `preventDefault`.
      ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
    } finally {
      TopLevelCallbackBookKeeping.release(bookKeeping);
    }
  }
};

module.exports = ReactEventListener;

/***/ }),
/* 160 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */



/**
 * Gets the scroll position of the supplied element or window.
 *
 * The return values are unbounded, unlike `getScrollPosition`. This means they
 * may be negative or exceed the element boundaries (which is possible using
 * inertial scrolling).
 *
 * @param {DOMWindow|DOMElement} scrollable
 * @return {object} Map with `x` and `y` keys.
 */

function getUnboundedScrollPosition(scrollable) {
  if (scrollable.Window && scrollable instanceof scrollable.Window) {
    return {
      x: scrollable.pageXOffset || scrollable.document.documentElement.scrollLeft,
      y: scrollable.pageYOffset || scrollable.document.documentElement.scrollTop
    };
  }
  return {
    x: scrollable.scrollLeft,
    y: scrollable.scrollTop
  };
}

module.exports = getUnboundedScrollPosition;

/***/ }),
/* 161 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMProperty = __webpack_require__(13);
var EventPluginHub = __webpack_require__(21);
var EventPluginUtils = __webpack_require__(36);
var ReactComponentEnvironment = __webpack_require__(45);
var ReactEmptyComponent = __webpack_require__(76);
var ReactBrowserEventEmitter = __webpack_require__(33);
var ReactHostComponent = __webpack_require__(77);
var ReactUpdates = __webpack_require__(10);

var ReactInjection = {
  Component: ReactComponentEnvironment.injection,
  DOMProperty: DOMProperty.injection,
  EmptyComponent: ReactEmptyComponent.injection,
  EventPluginHub: EventPluginHub.injection,
  EventPluginUtils: EventPluginUtils.injection,
  EventEmitter: ReactBrowserEventEmitter.injection,
  HostComponent: ReactHostComponent.injection,
  Updates: ReactUpdates.injection
};

module.exports = ReactInjection;

/***/ }),
/* 162 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _assign = __webpack_require__(3);

var CallbackQueue = __webpack_require__(63);
var PooledClass = __webpack_require__(15);
var ReactBrowserEventEmitter = __webpack_require__(33);
var ReactInputSelection = __webpack_require__(80);
var ReactInstrumentation = __webpack_require__(7);
var Transaction = __webpack_require__(29);
var ReactUpdateQueue = __webpack_require__(49);

/**
 * Ensures that, when possible, the selection range (currently selected text
 * input) is not disturbed by performing the transaction.
 */
var SELECTION_RESTORATION = {
  /**
   * @return {Selection} Selection information.
   */
  initialize: ReactInputSelection.getSelectionInformation,
  /**
   * @param {Selection} sel Selection information returned from `initialize`.
   */
  close: ReactInputSelection.restoreSelection
};

/**
 * Suppresses events (blur/focus) that could be inadvertently dispatched due to
 * high level DOM manipulations (like temporarily removing a text input from the
 * DOM).
 */
var EVENT_SUPPRESSION = {
  /**
   * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
   * the reconciliation.
   */
  initialize: function () {
    var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
    ReactBrowserEventEmitter.setEnabled(false);
    return currentlyEnabled;
  },

  /**
   * @param {boolean} previouslyEnabled Enabled status of
   *   `ReactBrowserEventEmitter` before the reconciliation occurred. `close`
   *   restores the previous value.
   */
  close: function (previouslyEnabled) {
    ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
  }
};

/**
 * Provides a queue for collecting `componentDidMount` and
 * `componentDidUpdate` callbacks during the transaction.
 */
var ON_DOM_READY_QUEUEING = {
  /**
   * Initializes the internal `onDOMReady` queue.
   */
  initialize: function () {
    this.reactMountReady.reset();
  },

  /**
   * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
   */
  close: function () {
    this.reactMountReady.notifyAll();
  }
};

/**
 * Executed within the scope of the `Transaction` instance. Consider these as
 * being member methods, but with an implied ordering while being isolated from
 * each other.
 */
var TRANSACTION_WRAPPERS = [SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING];

if (true) {
  TRANSACTION_WRAPPERS.push({
    initialize: ReactInstrumentation.debugTool.onBeginFlush,
    close: ReactInstrumentation.debugTool.onEndFlush
  });
}

/**
 * Currently:
 * - The order that these are listed in the transaction is critical:
 * - Suppresses events.
 * - Restores selection range.
 *
 * Future:
 * - Restore document/overflow scroll positions that were unintentionally
 *   modified via DOM insertions above the top viewport boundary.
 * - Implement/integrate with customized constraint based layout system and keep
 *   track of which dimensions must be remeasured.
 *
 * @class ReactReconcileTransaction
 */
function ReactReconcileTransaction(useCreateElement) {
  this.reinitializeTransaction();
  // Only server-side rendering really needs this option (see
  // `ReactServerRendering`), but server-side uses
  // `ReactServerRenderingTransaction` instead. This option is here so that it's
  // accessible and defaults to false when `ReactDOMComponent` and
  // `ReactDOMTextComponent` checks it in `mountComponent`.`
  this.renderToStaticMarkup = false;
  this.reactMountReady = CallbackQueue.getPooled(null);
  this.useCreateElement = useCreateElement;
}

var Mixin = {
  /**
   * @see Transaction
   * @abstract
   * @final
   * @return {array<object>} List of operation wrap procedures.
   *   TODO: convert to array<TransactionWrapper>
   */
  getTransactionWrappers: function () {
    return TRANSACTION_WRAPPERS;
  },

  /**
   * @return {object} The queue to collect `onDOMReady` callbacks with.
   */
  getReactMountReady: function () {
    return this.reactMountReady;
  },

  /**
   * @return {object} The queue to collect React async events.
   */
  getUpdateQueue: function () {
    return ReactUpdateQueue;
  },

  /**
   * Save current transaction state -- if the return value from this method is
   * passed to `rollback`, the transaction will be reset to that state.
   */
  checkpoint: function () {
    // reactMountReady is the our only stateful wrapper
    return this.reactMountReady.checkpoint();
  },

  rollback: function (checkpoint) {
    this.reactMountReady.rollback(checkpoint);
  },

  /**
   * `PooledClass` looks for this, and will invoke this before allowing this
   * instance to be reused.
   */
  destructor: function () {
    CallbackQueue.release(this.reactMountReady);
    this.reactMountReady = null;
  }
};

_assign(ReactReconcileTransaction.prototype, Transaction, Mixin);

PooledClass.addPoolingTo(ReactReconcileTransaction);

module.exports = ReactReconcileTransaction;

/***/ }),
/* 163 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ExecutionEnvironment = __webpack_require__(5);

var getNodeForCharacterOffset = __webpack_require__(164);
var getTextContentAccessor = __webpack_require__(62);

/**
 * While `isCollapsed` is available on the Selection object and `collapsed`
 * is available on the Range object, IE11 sometimes gets them wrong.
 * If the anchor/focus nodes and offsets are the same, the range is collapsed.
 */
function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
  return anchorNode === focusNode && anchorOffset === focusOffset;
}

/**
 * Get the appropriate anchor and focus node/offset pairs for IE.
 *
 * The catch here is that IE's selection API doesn't provide information
 * about whether the selection is forward or backward, so we have to
 * behave as though it's always forward.
 *
 * IE text differs from modern selection in that it behaves as though
 * block elements end with a new line. This means character offsets will
 * differ between the two APIs.
 *
 * @param {DOMElement} node
 * @return {object}
 */
function getIEOffsets(node) {
  var selection = document.selection;
  var selectedRange = selection.createRange();
  var selectedLength = selectedRange.text.length;

  // Duplicate selection so we can move range without breaking user selection.
  var fromStart = selectedRange.duplicate();
  fromStart.moveToElementText(node);
  fromStart.setEndPoint('EndToStart', selectedRange);

  var startOffset = fromStart.text.length;
  var endOffset = startOffset + selectedLength;

  return {
    start: startOffset,
    end: endOffset
  };
}

/**
 * @param {DOMElement} node
 * @return {?object}
 */
function getModernOffsets(node) {
  var selection = window.getSelection && window.getSelection();

  if (!selection || selection.rangeCount === 0) {
    return null;
  }

  var anchorNode = selection.anchorNode;
  var anchorOffset = selection.anchorOffset;
  var focusNode = selection.focusNode;
  var focusOffset = selection.focusOffset;

  var currentRange = selection.getRangeAt(0);

  // In Firefox, range.startContainer and range.endContainer can be "anonymous
  // divs", e.g. the up/down buttons on an <input type="number">. Anonymous
  // divs do not seem to expose properties, triggering a "Permission denied
  // error" if any of its properties are accessed. The only seemingly possible
  // way to avoid erroring is to access a property that typically works for
  // non-anonymous divs and catch any error that may otherwise arise. See
  // https://bugzilla.mozilla.org/show_bug.cgi?id=208427
  try {
    /* eslint-disable no-unused-expressions */
    currentRange.startContainer.nodeType;
    currentRange.endContainer.nodeType;
    /* eslint-enable no-unused-expressions */
  } catch (e) {
    return null;
  }

  // If the node and offset values are the same, the selection is collapsed.
  // `Selection.isCollapsed` is available natively, but IE sometimes gets
  // this value wrong.
  var isSelectionCollapsed = isCollapsed(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset);

  var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;

  var tempRange = currentRange.cloneRange();
  tempRange.selectNodeContents(node);
  tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);

  var isTempRangeCollapsed = isCollapsed(tempRange.startContainer, tempRange.startOffset, tempRange.endContainer, tempRange.endOffset);

  var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
  var end = start + rangeLength;

  // Detect whether the selection is backward.
  var detectionRange = document.createRange();
  detectionRange.setStart(anchorNode, anchorOffset);
  detectionRange.setEnd(focusNode, focusOffset);
  var isBackward = detectionRange.collapsed;

  return {
    start: isBackward ? end : start,
    end: isBackward ? start : end
  };
}

/**
 * @param {DOMElement|DOMTextNode} node
 * @param {object} offsets
 */
function setIEOffsets(node, offsets) {
  var range = document.selection.createRange().duplicate();
  var start, end;

  if (offsets.end === undefined) {
    start = offsets.start;
    end = start;
  } else if (offsets.start > offsets.end) {
    start = offsets.end;
    end = offsets.start;
  } else {
    start = offsets.start;
    end = offsets.end;
  }

  range.moveToElementText(node);
  range.moveStart('character', start);
  range.setEndPoint('EndToStart', range);
  range.moveEnd('character', end - start);
  range.select();
}

/**
 * In modern non-IE browsers, we can support both forward and backward
 * selections.
 *
 * Note: IE10+ supports the Selection object, but it does not support
 * the `extend` method, which means that even in modern IE, it's not possible
 * to programmatically create a backward selection. Thus, for all IE
 * versions, we use the old IE API to create our selections.
 *
 * @param {DOMElement|DOMTextNode} node
 * @param {object} offsets
 */
function setModernOffsets(node, offsets) {
  if (!window.getSelection) {
    return;
  }

  var selection = window.getSelection();
  var length = node[getTextContentAccessor()].length;
  var start = Math.min(offsets.start, length);
  var end = offsets.end === undefined ? start : Math.min(offsets.end, length);

  // IE 11 uses modern selection, but doesn't support the extend method.
  // Flip backward selections, so we can set with a single range.
  if (!selection.extend && start > end) {
    var temp = end;
    end = start;
    start = temp;
  }

  var startMarker = getNodeForCharacterOffset(node, start);
  var endMarker = getNodeForCharacterOffset(node, end);

  if (startMarker && endMarker) {
    var range = document.createRange();
    range.setStart(startMarker.node, startMarker.offset);
    selection.removeAllRanges();

    if (start > end) {
      selection.addRange(range);
      selection.extend(endMarker.node, endMarker.offset);
    } else {
      range.setEnd(endMarker.node, endMarker.offset);
      selection.addRange(range);
    }
  }
}

var useIEOffsets = ExecutionEnvironment.canUseDOM && 'selection' in document && !('getSelection' in window);

var ReactDOMSelection = {
  /**
   * @param {DOMElement} node
   */
  getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,

  /**
   * @param {DOMElement|DOMTextNode} node
   * @param {object} offsets
   */
  setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
};

module.exports = ReactDOMSelection;

/***/ }),
/* 164 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



/**
 * Given any node return the first leaf node without children.
 *
 * @param {DOMElement|DOMTextNode} node
 * @return {DOMElement|DOMTextNode}
 */

function getLeafNode(node) {
  while (node && node.firstChild) {
    node = node.firstChild;
  }
  return node;
}

/**
 * Get the next sibling within a container. This will walk up the
 * DOM if a node's siblings have been exhausted.
 *
 * @param {DOMElement|DOMTextNode} node
 * @return {?DOMElement|DOMTextNode}
 */
function getSiblingNode(node) {
  while (node) {
    if (node.nextSibling) {
      return node.nextSibling;
    }
    node = node.parentNode;
  }
}

/**
 * Get object describing the nodes which contain characters at offset.
 *
 * @param {DOMElement|DOMTextNode} root
 * @param {number} offset
 * @return {?object}
 */
function getNodeForCharacterOffset(root, offset) {
  var node = getLeafNode(root);
  var nodeStart = 0;
  var nodeEnd = 0;

  while (node) {
    if (node.nodeType === 3) {
      nodeEnd = nodeStart + node.textContent.length;

      if (nodeStart <= offset && nodeEnd >= offset) {
        return {
          node: node,
          offset: offset - nodeStart
        };
      }

      nodeStart = nodeEnd;
    }

    node = getLeafNode(getSiblingNode(node));
  }
}

module.exports = getNodeForCharacterOffset;

/***/ }),
/* 165 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */

var isTextNode = __webpack_require__(166);

/*eslint-disable no-bitwise */

/**
 * Checks if a given DOM node contains or is another DOM node.
 */
function containsNode(outerNode, innerNode) {
  if (!outerNode || !innerNode) {
    return false;
  } else if (outerNode === innerNode) {
    return true;
  } else if (isTextNode(outerNode)) {
    return false;
  } else if (isTextNode(innerNode)) {
    return containsNode(outerNode, innerNode.parentNode);
  } else if ('contains' in outerNode) {
    return outerNode.contains(innerNode);
  } else if (outerNode.compareDocumentPosition) {
    return !!(outerNode.compareDocumentPosition(innerNode) & 16);
  } else {
    return false;
  }
}

module.exports = containsNode;

/***/ }),
/* 166 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

var isNode = __webpack_require__(167);

/**
 * @param {*} object The object to check.
 * @return {boolean} Whether or not the object is a DOM text node.
 */
function isTextNode(object) {
  return isNode(object) && object.nodeType == 3;
}

module.exports = isTextNode;

/***/ }),
/* 167 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @typechecks
 */

/**
 * @param {*} object The object to check.
 * @return {boolean} Whether or not the object is a DOM node.
 */
function isNode(object) {
  var doc = object ? object.ownerDocument || object : document;
  var defaultView = doc.defaultView || window;
  return !!(object && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
}

module.exports = isNode;

/***/ }),
/* 168 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var NS = {
  xlink: 'http://www.w3.org/1999/xlink',
  xml: 'http://www.w3.org/XML/1998/namespace'
};

// We use attributes for everything SVG so let's avoid some duplication and run
// code instead.
// The following are all specified in the HTML config already so we exclude here.
// - class (as className)
// - color
// - height
// - id
// - lang
// - max
// - media
// - method
// - min
// - name
// - style
// - target
// - type
// - width
var ATTRS = {
  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'
};

var SVGDOMPropertyConfig = {
  Properties: {},
  DOMAttributeNamespaces: {
    xlinkActuate: NS.xlink,
    xlinkArcrole: NS.xlink,
    xlinkHref: NS.xlink,
    xlinkRole: NS.xlink,
    xlinkShow: NS.xlink,
    xlinkTitle: NS.xlink,
    xlinkType: NS.xlink,
    xmlBase: NS.xml,
    xmlLang: NS.xml,
    xmlSpace: NS.xml
  },
  DOMAttributeNames: {}
};

Object.keys(ATTRS).forEach(function (key) {
  SVGDOMPropertyConfig.Properties[key] = 0;
  if (ATTRS[key]) {
    SVGDOMPropertyConfig.DOMAttributeNames[key] = ATTRS[key];
  }
});

module.exports = SVGDOMPropertyConfig;

/***/ }),
/* 169 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var EventPropagators = __webpack_require__(20);
var ExecutionEnvironment = __webpack_require__(5);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactInputSelection = __webpack_require__(80);
var SyntheticEvent = __webpack_require__(12);

var getActiveElement = __webpack_require__(81);
var isTextInputElement = __webpack_require__(66);
var shallowEqual = __webpack_require__(46);

var skipSelectionChangeEvent = ExecutionEnvironment.canUseDOM && 'documentMode' in document && document.documentMode <= 11;

var eventTypes = {
  select: {
    phasedRegistrationNames: {
      bubbled: 'onSelect',
      captured: 'onSelectCapture'
    },
    dependencies: ['topBlur', 'topContextMenu', 'topFocus', 'topKeyDown', 'topKeyUp', 'topMouseDown', 'topMouseUp', 'topSelectionChange']
  }
};

var activeElement = null;
var activeElementInst = null;
var lastSelection = null;
var mouseDown = false;

// Track whether a listener exists for this plugin. If none exist, we do
// not extract events. See #3639.
var hasListener = false;

/**
 * Get an object which is a unique representation of the current selection.
 *
 * The return value will not be consistent across nodes or browsers, but
 * two identical selections on the same node will return identical objects.
 *
 * @param {DOMElement} node
 * @return {object}
 */
function getSelection(node) {
  if ('selectionStart' in node && ReactInputSelection.hasSelectionCapabilities(node)) {
    return {
      start: node.selectionStart,
      end: node.selectionEnd
    };
  } else if (window.getSelection) {
    var selection = window.getSelection();
    return {
      anchorNode: selection.anchorNode,
      anchorOffset: selection.anchorOffset,
      focusNode: selection.focusNode,
      focusOffset: selection.focusOffset
    };
  } else if (document.selection) {
    var range = document.selection.createRange();
    return {
      parentElement: range.parentElement(),
      text: range.text,
      top: range.boundingTop,
      left: range.boundingLeft
    };
  }
}

/**
 * Poll selection to see whether it's changed.
 *
 * @param {object} nativeEvent
 * @return {?SyntheticEvent}
 */
function constructSelectEvent(nativeEvent, nativeEventTarget) {
  // Ensure we have the right element, and that the user is not dragging a
  // selection (this matches native `select` event behavior). In HTML5, select
  // fires only on input and textarea thus if there's no focused element we
  // won't dispatch.
  if (mouseDown || activeElement == null || activeElement !== getActiveElement()) {
    return null;
  }

  // Only fire when selection has actually changed.
  var currentSelection = getSelection(activeElement);
  if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
    lastSelection = currentSelection;

    var syntheticEvent = SyntheticEvent.getPooled(eventTypes.select, activeElementInst, nativeEvent, nativeEventTarget);

    syntheticEvent.type = 'select';
    syntheticEvent.target = activeElement;

    EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);

    return syntheticEvent;
  }

  return null;
}

/**
 * This plugin creates an `onSelect` event that normalizes select events
 * across form elements.
 *
 * Supported elements are:
 * - input (see `isTextInputElement`)
 * - textarea
 * - contentEditable
 *
 * This differs from native browser implementations in the following ways:
 * - Fires on contentEditable fields as well as inputs.
 * - Fires for collapsed selection.
 * - Fires after user input.
 */
var SelectEventPlugin = {
  eventTypes: eventTypes,

  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    if (!hasListener) {
      return null;
    }

    var targetNode = targetInst ? ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;

    switch (topLevelType) {
      // Track the input node that has focus.
      case 'topFocus':
        if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') {
          activeElement = targetNode;
          activeElementInst = targetInst;
          lastSelection = null;
        }
        break;
      case 'topBlur':
        activeElement = null;
        activeElementInst = null;
        lastSelection = null;
        break;
      // Don't fire the event while the user is dragging. This matches the
      // semantics of the native select event.
      case 'topMouseDown':
        mouseDown = true;
        break;
      case 'topContextMenu':
      case 'topMouseUp':
        mouseDown = false;
        return constructSelectEvent(nativeEvent, nativeEventTarget);
      // Chrome and IE fire non-standard event when selection is changed (and
      // sometimes when it hasn't). IE's event fires out of order with respect
      // to key and input events on deletion, so we discard it.
      //
      // Firefox doesn't support selectionchange, so check selection status
      // after each key entry. The selection changes after keydown and before
      // keyup, but we check on keydown as well in the case of holding down a
      // key, when multiple keydown events are fired but only one keyup is.
      // This is also our approach for IE handling, for the reason above.
      case 'topSelectionChange':
        if (skipSelectionChangeEvent) {
          break;
        }
      // falls through
      case 'topKeyDown':
      case 'topKeyUp':
        return constructSelectEvent(nativeEvent, nativeEventTarget);
    }

    return null;
  },

  didPutListener: function (inst, registrationName, listener) {
    if (registrationName === 'onSelect') {
      hasListener = true;
    }
  }
};

module.exports = SelectEventPlugin;

/***/ }),
/* 170 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var _prodInvariant = __webpack_require__(2);

var EventListener = __webpack_require__(79);
var EventPropagators = __webpack_require__(20);
var ReactDOMComponentTree = __webpack_require__(4);
var SyntheticAnimationEvent = __webpack_require__(171);
var SyntheticClipboardEvent = __webpack_require__(172);
var SyntheticEvent = __webpack_require__(12);
var SyntheticFocusEvent = __webpack_require__(173);
var SyntheticKeyboardEvent = __webpack_require__(174);
var SyntheticMouseEvent = __webpack_require__(30);
var SyntheticDragEvent = __webpack_require__(176);
var SyntheticTouchEvent = __webpack_require__(177);
var SyntheticTransitionEvent = __webpack_require__(178);
var SyntheticUIEvent = __webpack_require__(22);
var SyntheticWheelEvent = __webpack_require__(179);

var emptyFunction = __webpack_require__(8);
var getEventCharCode = __webpack_require__(51);
var invariant = __webpack_require__(0);

/**
 * Turns
 * ['abort', ...]
 * into
 * eventTypes = {
 *   'abort': {
 *     phasedRegistrationNames: {
 *       bubbled: 'onAbort',
 *       captured: 'onAbortCapture',
 *     },
 *     dependencies: ['topAbort'],
 *   },
 *   ...
 * };
 * topLevelEventsToDispatchConfig = {
 *   'topAbort': { sameConfig }
 * };
 */
var eventTypes = {};
var topLevelEventsToDispatchConfig = {};
['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 (event) {
  var capitalizedEvent = event[0].toUpperCase() + event.slice(1);
  var onEvent = 'on' + capitalizedEvent;
  var topEvent = 'top' + capitalizedEvent;

  var type = {
    phasedRegistrationNames: {
      bubbled: onEvent,
      captured: onEvent + 'Capture'
    },
    dependencies: [topEvent]
  };
  eventTypes[event] = type;
  topLevelEventsToDispatchConfig[topEvent] = type;
});

var onClickListeners = {};

function getDictionaryKey(inst) {
  // Prevents V8 performance issue:
  // https://github.com/facebook/react/pull/7232
  return '.' + inst._rootNodeID;
}

function isInteractive(tag) {
  return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';
}

var SimpleEventPlugin = {
  eventTypes: eventTypes,

  extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
    var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
    if (!dispatchConfig) {
      return null;
    }
    var EventConstructor;
    switch (topLevelType) {
      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':
        // HTML Events
        // @see http://www.w3.org/TR/html5/index.html#events-0
        EventConstructor = SyntheticEvent;
        break;
      case 'topKeyPress':
        // Firefox creates a keypress event for function keys too. This removes
        // the unwanted keypress events. Enter is however both printable and
        // non-printable. One would expect Tab to be as well (but it isn't).
        if (getEventCharCode(nativeEvent) === 0) {
          return null;
        }
      /* falls through */
      case 'topKeyDown':
      case 'topKeyUp':
        EventConstructor = SyntheticKeyboardEvent;
        break;
      case 'topBlur':
      case 'topFocus':
        EventConstructor = SyntheticFocusEvent;
        break;
      case 'topClick':
        // Firefox creates a click event on right mouse clicks. This removes the
        // unwanted click events.
        if (nativeEvent.button === 2) {
          return null;
        }
      /* falls through */
      case 'topDoubleClick':
      case 'topMouseDown':
      case 'topMouseMove':
      case 'topMouseUp':
      // TODO: Disabled elements should not respond to mouse events
      /* falls through */
      case 'topMouseOut':
      case 'topMouseOver':
      case 'topContextMenu':
        EventConstructor = SyntheticMouseEvent;
        break;
      case 'topDrag':
      case 'topDragEnd':
      case 'topDragEnter':
      case 'topDragExit':
      case 'topDragLeave':
      case 'topDragOver':
      case 'topDragStart':
      case 'topDrop':
        EventConstructor = SyntheticDragEvent;
        break;
      case 'topTouchCancel':
      case 'topTouchEnd':
      case 'topTouchMove':
      case 'topTouchStart':
        EventConstructor = SyntheticTouchEvent;
        break;
      case 'topAnimationEnd':
      case 'topAnimationIteration':
      case 'topAnimationStart':
        EventConstructor = SyntheticAnimationEvent;
        break;
      case 'topTransitionEnd':
        EventConstructor = SyntheticTransitionEvent;
        break;
      case 'topScroll':
        EventConstructor = SyntheticUIEvent;
        break;
      case 'topWheel':
        EventConstructor = SyntheticWheelEvent;
        break;
      case 'topCopy':
      case 'topCut':
      case 'topPaste':
        EventConstructor = SyntheticClipboardEvent;
        break;
    }
    !EventConstructor ?  true ? invariant(false, 'SimpleEventPlugin: Unhandled event type, `%s`.', topLevelType) : _prodInvariant('86', topLevelType) : void 0;
    var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget);
    EventPropagators.accumulateTwoPhaseDispatches(event);
    return event;
  },

  didPutListener: function (inst, registrationName, listener) {
    // Mobile Safari does not fire properly bubble click events on
    // non-interactive elements, which means delegated click listeners do not
    // fire. The workaround for this bug involves attaching an empty click
    // listener on the target node.
    // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
    if (registrationName === 'onClick' && !isInteractive(inst._tag)) {
      var key = getDictionaryKey(inst);
      var node = ReactDOMComponentTree.getNodeFromInstance(inst);
      if (!onClickListeners[key]) {
        onClickListeners[key] = EventListener.listen(node, 'click', emptyFunction);
      }
    }
  },

  willDeleteListener: function (inst, registrationName) {
    if (registrationName === 'onClick' && !isInteractive(inst._tag)) {
      var key = getDictionaryKey(inst);
      onClickListeners[key].remove();
      delete onClickListeners[key];
    }
  }
};

module.exports = SimpleEventPlugin;

/***/ }),
/* 171 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

/**
 * @interface Event
 * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
 * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
 */
var AnimationEventInterface = {
  animationName: null,
  elapsedTime: null,
  pseudoElement: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticEvent}
 */
function SyntheticAnimationEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticAnimationEvent, AnimationEventInterface);

module.exports = SyntheticAnimationEvent;

/***/ }),
/* 172 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

/**
 * @interface Event
 * @see http://www.w3.org/TR/clipboard-apis/
 */
var ClipboardEventInterface = {
  clipboardData: function (event) {
    return 'clipboardData' in event ? event.clipboardData : window.clipboardData;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);

module.exports = SyntheticClipboardEvent;

/***/ }),
/* 173 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticUIEvent = __webpack_require__(22);

/**
 * @interface FocusEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var FocusEventInterface = {
  relatedTarget: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);

module.exports = SyntheticFocusEvent;

/***/ }),
/* 174 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticUIEvent = __webpack_require__(22);

var getEventCharCode = __webpack_require__(51);
var getEventKey = __webpack_require__(175);
var getEventModifierState = __webpack_require__(40);

/**
 * @interface KeyboardEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var KeyboardEventInterface = {
  key: getEventKey,
  location: null,
  ctrlKey: null,
  shiftKey: null,
  altKey: null,
  metaKey: null,
  repeat: null,
  locale: null,
  getModifierState: getEventModifierState,
  // Legacy Interface
  charCode: function (event) {
    // `charCode` is the result of a KeyPress event and represents the value of
    // the actual printable character.

    // KeyPress is deprecated, but its replacement is not yet final and not
    // implemented in any major browser. Only KeyPress has charCode.
    if (event.type === 'keypress') {
      return getEventCharCode(event);
    }
    return 0;
  },
  keyCode: function (event) {
    // `keyCode` is the result of a KeyDown/Up event and represents the value of
    // physical keyboard key.

    // The actual meaning of the value depends on the users' keyboard layout
    // which cannot be detected. Assuming that it is a US keyboard layout
    // provides a surprisingly accurate mapping for US and European users.
    // Due to this, it is left to the user to implement at this time.
    if (event.type === 'keydown' || event.type === 'keyup') {
      return event.keyCode;
    }
    return 0;
  },
  which: function (event) {
    // `which` is an alias for either `keyCode` or `charCode` depending on the
    // type of the event.
    if (event.type === 'keypress') {
      return getEventCharCode(event);
    }
    if (event.type === 'keydown' || event.type === 'keyup') {
      return event.keyCode;
    }
    return 0;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);

module.exports = SyntheticKeyboardEvent;

/***/ }),
/* 175 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var getEventCharCode = __webpack_require__(51);

/**
 * Normalization of deprecated HTML5 `key` values
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
 */
var normalizeKey = {
  Esc: 'Escape',
  Spacebar: ' ',
  Left: 'ArrowLeft',
  Up: 'ArrowUp',
  Right: 'ArrowRight',
  Down: 'ArrowDown',
  Del: 'Delete',
  Win: 'OS',
  Menu: 'ContextMenu',
  Apps: 'ContextMenu',
  Scroll: 'ScrollLock',
  MozPrintableKey: 'Unidentified'
};

/**
 * Translation from legacy `keyCode` to HTML5 `key`
 * Only special keys supported, all others depend on keyboard layout or browser
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
 */
var translateToKey = {
  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'
};

/**
 * @param {object} nativeEvent Native browser event.
 * @return {string} Normalized `key` property.
 */
function getEventKey(nativeEvent) {
  if (nativeEvent.key) {
    // Normalize inconsistent values reported by browsers due to
    // implementations of a working draft specification.

    // FireFox implements `key` but returns `MozPrintableKey` for all
    // printable characters (normalized to `Unidentified`), ignore it.
    var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
    if (key !== 'Unidentified') {
      return key;
    }
  }

  // Browser does not implement `key`, polyfill as much of it as we can.
  if (nativeEvent.type === 'keypress') {
    var charCode = getEventCharCode(nativeEvent);

    // The enter-key is technically both printable and non-printable and can
    // thus be captured by `keypress`, no other non-printable key should.
    return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
  }
  if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
    // While user keyboard layout determines the actual meaning of each
    // `keyCode` value, almost all function keys have a universal value.
    return translateToKey[nativeEvent.keyCode] || 'Unidentified';
  }
  return '';
}

module.exports = getEventKey;

/***/ }),
/* 176 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticMouseEvent = __webpack_require__(30);

/**
 * @interface DragEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var DragEventInterface = {
  dataTransfer: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);

module.exports = SyntheticDragEvent;

/***/ }),
/* 177 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticUIEvent = __webpack_require__(22);

var getEventModifierState = __webpack_require__(40);

/**
 * @interface TouchEvent
 * @see http://www.w3.org/TR/touch-events/
 */
var TouchEventInterface = {
  touches: null,
  targetTouches: null,
  changedTouches: null,
  altKey: null,
  metaKey: null,
  ctrlKey: null,
  shiftKey: null,
  getModifierState: getEventModifierState
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);

module.exports = SyntheticTouchEvent;

/***/ }),
/* 178 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticEvent = __webpack_require__(12);

/**
 * @interface Event
 * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
 * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
 */
var TransitionEventInterface = {
  propertyName: null,
  elapsedTime: null,
  pseudoElement: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticEvent}
 */
function SyntheticTransitionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticEvent.augmentClass(SyntheticTransitionEvent, TransitionEventInterface);

module.exports = SyntheticTransitionEvent;

/***/ }),
/* 179 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var SyntheticMouseEvent = __webpack_require__(30);

/**
 * @interface WheelEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var WheelEventInterface = {
  deltaX: function (event) {
    return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
    'wheelDeltaX' in event ? -event.wheelDeltaX : 0;
  },
  deltaY: function (event) {
    return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
    'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
    'wheelDelta' in event ? -event.wheelDelta : 0;
  },
  deltaZ: null,

  // Browsers without "deltaMode" is reporting in raw wheel delta where one
  // notch on the scroll is always +/- 120, roughly equivalent to pixels.
  // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
  // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
  deltaMode: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticMouseEvent}
 */
function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
  return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
}

SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);

module.exports = SyntheticWheelEvent;

/***/ }),
/* 180 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var validateDOMNesting = __webpack_require__(50);

var DOC_NODE_TYPE = 9;

function ReactDOMContainerInfo(topLevelWrapper, node) {
  var info = {
    _topLevelWrapper: topLevelWrapper,
    _idCounter: 1,
    _ownerDocument: node ? node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument : null,
    _node: node,
    _tag: node ? node.nodeName.toLowerCase() : null,
    _namespaceURI: node ? node.namespaceURI : null
  };
  if (true) {
    info._ancestorInfo = node ? validateDOMNesting.updatedAncestorInfo(null, info._tag, null) : null;
  }
  return info;
}

module.exports = ReactDOMContainerInfo;

/***/ }),
/* 181 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactDOMFeatureFlags = {
  useCreateElement: true,
  useFiber: false
};

module.exports = ReactDOMFeatureFlags;

/***/ }),
/* 182 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var adler32 = __webpack_require__(183);

var TAG_END = /\/?>/;
var COMMENT_START = /^<\!\-\-/;

var ReactMarkupChecksum = {
  CHECKSUM_ATTR_NAME: 'data-react-checksum',

  /**
   * @param {string} markup Markup string
   * @return {string} Markup string with checksum attribute attached
   */
  addChecksumToMarkup: function (markup) {
    var checksum = adler32(markup);

    // Add checksum (handle both parent tags, comments and self-closing tags)
    if (COMMENT_START.test(markup)) {
      return markup;
    } else {
      return markup.replace(TAG_END, ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '"$&');
    }
  },

  /**
   * @param {string} markup to use
   * @param {DOMElement} element root React element
   * @returns {boolean} whether or not the markup is the same
   */
  canReuseMarkup: function (markup, element) {
    var existingChecksum = element.getAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
    existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
    var markupChecksum = adler32(markup);
    return markupChecksum === existingChecksum;
  }
};

module.exports = ReactMarkupChecksum;

/***/ }),
/* 183 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */



var MOD = 65521;

// adler32 is not cryptographically strong, and is only used to sanity check that
// markup generated on the server matches the markup generated on the client.
// This implementation (a modified version of the SheetJS version) has been optimized
// for our use case, at the expense of conforming to the adler32 specification
// for non-ascii inputs.
function adler32(data) {
  var a = 1;
  var b = 0;
  var i = 0;
  var l = data.length;
  var m = l & ~0x3;
  while (i < m) {
    var n = Math.min(i + 4096, m);
    for (; i < n; i += 4) {
      b += (a += data.charCodeAt(i)) + (a += data.charCodeAt(i + 1)) + (a += data.charCodeAt(i + 2)) + (a += data.charCodeAt(i + 3));
    }
    a %= MOD;
    b %= MOD;
  }
  for (; i < l; i++) {
    b += a += data.charCodeAt(i);
  }
  a %= MOD;
  b %= MOD;
  return a | b << 16;
}

module.exports = adler32;

/***/ }),
/* 184 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



module.exports = '15.6.2';

/***/ }),
/* 185 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var _prodInvariant = __webpack_require__(2);

var ReactCurrentOwner = __webpack_require__(9);
var ReactDOMComponentTree = __webpack_require__(4);
var ReactInstanceMap = __webpack_require__(23);

var getHostComponentFromComposite = __webpack_require__(83);
var invariant = __webpack_require__(0);
var warning = __webpack_require__(1);

/**
 * Returns the DOM node rendered by this element.
 *
 * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
 *
 * @param {ReactComponent|DOMElement} componentOrElement
 * @return {?DOMElement} The root node of this element.
 */
function findDOMNode(componentOrElement) {
  if (true) {
    var owner = ReactCurrentOwner.current;
    if (owner !== null) {
       true ? warning(owner._warnedAboutRefsInRender, '%s is accessing findDOMNode inside its render(). ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', owner.getName() || 'A component') : void 0;
      owner._warnedAboutRefsInRender = true;
    }
  }
  if (componentOrElement == null) {
    return null;
  }
  if (componentOrElement.nodeType === 1) {
    return componentOrElement;
  }

  var inst = ReactInstanceMap.get(componentOrElement);
  if (inst) {
    inst = getHostComponentFromComposite(inst);
    return inst ? ReactDOMComponentTree.getNodeFromInstance(inst) : null;
  }

  if (typeof componentOrElement.render === 'function') {
     true ?  true ? invariant(false, 'findDOMNode was called on an unmounted component.') : _prodInvariant('44') : void 0;
  } else {
     true ?  true ? invariant(false, 'Element appears to be neither ReactComponent nor DOMNode (keys: %s)', Object.keys(componentOrElement)) : _prodInvariant('45', Object.keys(componentOrElement)) : void 0;
  }
}

module.exports = findDOMNode;

/***/ }),
/* 186 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactMount = __webpack_require__(82);

module.exports = ReactMount.renderSubtreeIntoContainer;

/***/ }),
/* 187 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMProperty = __webpack_require__(13);
var EventPluginRegistry = __webpack_require__(28);
var ReactComponentTreeHook = __webpack_require__(6);

var warning = __webpack_require__(1);

if (true) {
  var reactProps = {
    children: true,
    dangerouslySetInnerHTML: true,
    key: true,
    ref: true,

    autoFocus: true,
    defaultValue: true,
    valueLink: true,
    defaultChecked: true,
    checkedLink: true,
    innerHTML: true,
    suppressContentEditableWarning: true,
    onFocusIn: true,
    onFocusOut: true
  };
  var warnedProperties = {};

  var validateProperty = function (tagName, name, debugID) {
    if (DOMProperty.properties.hasOwnProperty(name) || DOMProperty.isCustomAttribute(name)) {
      return true;
    }
    if (reactProps.hasOwnProperty(name) && reactProps[name] || warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
      return true;
    }
    if (EventPluginRegistry.registrationNameModules.hasOwnProperty(name)) {
      return true;
    }
    warnedProperties[name] = true;
    var lowerCasedName = name.toLowerCase();

    // data-* attributes should be lowercase; suggest the lowercase version
    var standardName = DOMProperty.isCustomAttribute(lowerCasedName) ? lowerCasedName : DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ? DOMProperty.getPossibleStandardName[lowerCasedName] : null;

    var registrationName = EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? EventPluginRegistry.possibleRegistrationNames[lowerCasedName] : null;

    if (standardName != null) {
       true ? warning(false, 'Unknown DOM property %s. Did you mean %s?%s', name, standardName, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
      return true;
    } else if (registrationName != null) {
       true ? warning(false, 'Unknown event handler property %s. Did you mean `%s`?%s', name, registrationName, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
      return true;
    } else {
      // We were unable to guess which prop the user intended.
      // It is likely that the user was just blindly spreading/forwarding props
      // Components should be careful to only render valid props/attributes.
      // Warning will be invoked in warnUnknownProperties to allow grouping.
      return false;
    }
  };
}

var warnUnknownProperties = function (debugID, element) {
  var unknownProps = [];
  for (var key in element.props) {
    var isValid = validateProperty(element.type, key, debugID);
    if (!isValid) {
      unknownProps.push(key);
    }
  }

  var unknownPropString = unknownProps.map(function (prop) {
    return '`' + prop + '`';
  }).join(', ');

  if (unknownProps.length === 1) {
     true ? warning(false, 'Unknown prop %s on <%s> tag. Remove this prop from the element. ' + 'For details, see https://fb.me/react-unknown-prop%s', unknownPropString, element.type, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
  } else if (unknownProps.length > 1) {
     true ? warning(false, 'Unknown props %s on <%s> tag. Remove these props from the element. ' + 'For details, see https://fb.me/react-unknown-prop%s', unknownPropString, element.type, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
  }
};

function handleElement(debugID, element) {
  if (element == null || typeof element.type !== 'string') {
    return;
  }
  if (element.type.indexOf('-') >= 0 || element.props.is) {
    return;
  }
  warnUnknownProperties(debugID, element);
}

var ReactDOMUnknownPropertyHook = {
  onBeforeMountComponent: function (debugID, element) {
    handleElement(debugID, element);
  },
  onBeforeUpdateComponent: function (debugID, element) {
    handleElement(debugID, element);
  }
};

module.exports = ReactDOMUnknownPropertyHook;

/***/ }),
/* 188 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var ReactComponentTreeHook = __webpack_require__(6);

var warning = __webpack_require__(1);

var didWarnValueNull = false;

function handleElement(debugID, element) {
  if (element == null) {
    return;
  }
  if (element.type !== 'input' && element.type !== 'textarea' && element.type !== 'select') {
    return;
  }
  if (element.props != null && element.props.value === null && !didWarnValueNull) {
     true ? warning(false, '`value` prop on `%s` should not be null. ' + 'Consider using the empty string to clear the component or `undefined` ' + 'for uncontrolled components.%s', element.type, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;

    didWarnValueNull = true;
  }
}

var ReactDOMNullInputValuePropHook = {
  onBeforeMountComponent: function (debugID, element) {
    handleElement(debugID, element);
  },
  onBeforeUpdateComponent: function (debugID, element) {
    handleElement(debugID, element);
  }
};

module.exports = ReactDOMNullInputValuePropHook;

/***/ }),
/* 189 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */



var DOMProperty = __webpack_require__(13);
var ReactComponentTreeHook = __webpack_require__(6);

var warning = __webpack_require__(1);

var warnedProperties = {};
var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');

function validateProperty(tagName, name, debugID) {
  if (warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
    return true;
  }

  if (rARIA.test(name)) {
    var lowerCasedName = name.toLowerCase();
    var standardName = DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ? DOMProperty.getPossibleStandardName[lowerCasedName] : null;

    // If this is an aria-* attribute, but is not listed in the known DOM
    // DOM properties, then it is an invalid aria-* attribute.
    if (standardName == null) {
      warnedProperties[name] = true;
      return false;
    }
    // aria-* attributes should be lowercase; suggest the lowercase version.
    if (name !== standardName) {
       true ? warning(false, 'Unknown ARIA attribute %s. Did you mean %s?%s', name, standardName, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
      warnedProperties[name] = true;
      return true;
    }
  }

  return true;
}

function warnInvalidARIAProps(debugID, element) {
  var invalidProps = [];

  for (var key in element.props) {
    var isValid = validateProperty(element.type, key, debugID);
    if (!isValid) {
      invalidProps.push(key);
    }
  }

  var unknownPropString = invalidProps.map(function (prop) {
    return '`' + prop + '`';
  }).join(', ');

  if (invalidProps.length === 1) {
     true ? warning(false, 'Invalid aria prop %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, element.type, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
  } else if (invalidProps.length > 1) {
     true ? warning(false, 'Invalid aria props %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, element.type, ReactComponentTreeHook.getStackAddendumByID(debugID)) : void 0;
  }
}

function handleElement(debugID, element) {
  if (element == null || typeof element.type !== 'string') {
    return;
  }
  if (element.type.indexOf('-') >= 0 || element.props.is) {
    return;
  }

  warnInvalidARIAProps(debugID, element);
}

var ReactDOMInvalidARIAHook = {
  onBeforeMountComponent: function (debugID, element) {
    if (true) {
      handleElement(debugID, element);
    }
  },
  onBeforeUpdateComponent: function (debugID, element) {
    if (true) {
      handleElement(debugID, element);
    }
  }
};

module.exports = ReactDOMInvalidARIAHook;

/***/ }),
/* 190 */
/***/ (function(module, exports) {

var g;

// This works in non-strict mode
g = (function() {
    return this;
})();

try {
    // This works if eval is allowed (see CSP)
    g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
    // This works if the window reference is available
    if(typeof window === "object")
        g = window;
}

// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}

module.exports = g;


/***/ }),
/* 191 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(process) {

var utils = __webpack_require__(34);
var normalizeHeaderName = __webpack_require__(267);

var DEFAULT_CONTENT_TYPE = {
  'Content-Type': 'application/x-www-form-urlencoded'
};

function setContentTypeIfUnset(headers, value) {
  if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
    headers['Content-Type'] = value;
  }
}

function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = __webpack_require__(204);
  } else if (typeof process !== 'undefined') {
    // For node use HTTP adapter
    adapter = __webpack_require__(204);
  }
  return adapter;
}

var defaults = {
  adapter: getDefaultAdapter(),

  transformRequest: [function transformRequest(data, headers) {
    normalizeHeaderName(headers, 'Content-Type');
    if (utils.isFormData(data) ||
      utils.isArrayBuffer(data) ||
      utils.isBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data)
    ) {
      return data;
    }
    if (utils.isArrayBufferView(data)) {
      return data.buffer;
    }
    if (utils.isURLSearchParams(data)) {
      setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
      return data.toString();
    }
    if (utils.isObject(data)) {
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }
    return data;
  }],

  transformResponse: [function transformResponse(data) {
    /*eslint no-param-reassign:0*/
    if (typeof data === 'string') {
      try {
        data = JSON.parse(data);
      } catch (e) { /* Ignore */ }
    }
    return data;
  }],

  timeout: 0,

  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',

  maxContentLength: -1,

  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300;
  }
};

defaults.headers = {
  common: {
    'Accept': 'application/json, text/plain, */*'
  }
};

utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
  defaults.headers[method] = {};
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});

module.exports = defaults;

/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)))

/***/ }),
/* 192 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTargetCube", function() { return WebGLRenderTargetCube; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTarget", function() { return WebGLRenderTarget; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderer", function() { return WebGLRenderer; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderLib", function() { return ShaderLib; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsLib", function() { return UniformsLib; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsUtils", function() { return UniformsUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderChunk", function() { return ShaderChunk; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FogExp2", function() { return FogExp2; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Fog", function() { return Fog; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Scene", function() { return Scene; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LensFlare", function() { return LensFlare; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sprite", function() { return Sprite; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LOD", function() { return LOD; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkinnedMesh", function() { return SkinnedMesh; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Skeleton", function() { return Skeleton; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bone", function() { return Bone; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mesh", function() { return Mesh; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineSegments", function() { return LineSegments; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineLoop", function() { return LineLoop; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Points", function() { return Points; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Group", function() { return Group; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VideoTexture", function() { return VideoTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTexture", function() { return DataTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTexture", function() { return CompressedTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTexture", function() { return CubeTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasTexture", function() { return CanvasTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthTexture", function() { return DepthTexture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Texture", function() { return Texture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTextureLoader", function() { return CompressedTextureLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTextureLoader", function() { return DataTextureLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTextureLoader", function() { return CubeTextureLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureLoader", function() { return TextureLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectLoader", function() { return ObjectLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaterialLoader", function() { return MaterialLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometryLoader", function() { return BufferGeometryLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DefaultLoadingManager", function() { return DefaultLoadingManager; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoadingManager", function() { return LoadingManager; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "JSONLoader", function() { return JSONLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageLoader", function() { return ImageLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FontLoader", function() { return FontLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FileLoader", function() { return FileLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Loader", function() { return Loader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cache", function() { return Cache; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioLoader", function() { return AudioLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightShadow", function() { return SpotLightShadow; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLight", function() { return SpotLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLight", function() { return PointLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLight", function() { return RectAreaLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLight", function() { return HemisphereLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightShadow", function() { return DirectionalLightShadow; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLight", function() { return DirectionalLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AmbientLight", function() { return AmbientLight; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LightShadow", function() { return LightShadow; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Light", function() { return Light; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StereoCamera", function() { return StereoCamera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PerspectiveCamera", function() { return PerspectiveCamera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OrthographicCamera", function() { return OrthographicCamera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeCamera", function() { return CubeCamera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayCamera", function() { return ArrayCamera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Camera", function() { return Camera; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioListener", function() { return AudioListener; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PositionalAudio", function() { return PositionalAudio; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioContext", function() { return AudioContext; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioAnalyser", function() { return AudioAnalyser; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Audio", function() { return Audio; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VectorKeyframeTrack", function() { return VectorKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StringKeyframeTrack", function() { return StringKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionKeyframeTrack", function() { return QuaternionKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NumberKeyframeTrack", function() { return NumberKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorKeyframeTrack", function() { return ColorKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BooleanKeyframeTrack", function() { return BooleanKeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyMixer", function() { return PropertyMixer; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyBinding", function() { return PropertyBinding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyframeTrack", function() { return KeyframeTrack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationUtils", function() { return AnimationUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationObjectGroup", function() { return AnimationObjectGroup; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationMixer", function() { return AnimationMixer; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationClip", function() { return AnimationClip; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uniform", function() { return Uniform; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferGeometry", function() { return InstancedBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometry", function() { return BufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryIdCount", function() { return GeometryIdCount; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Geometry", function() { return Geometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBufferAttribute", function() { return InterleavedBufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedInterleavedBuffer", function() { return InstancedInterleavedBuffer; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBuffer", function() { return InterleavedBuffer; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferAttribute", function() { return InstancedBufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face3", function() { return Face3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Object3D", function() { return Object3D; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Raycaster", function() { return Raycaster; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Layers", function() { return Layers; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventDispatcher", function() { return EventDispatcher; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Clock", function() { return Clock; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionLinearInterpolant", function() { return QuaternionLinearInterpolant; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearInterpolant", function() { return LinearInterpolant; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscreteInterpolant", function() { return DiscreteInterpolant; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicInterpolant", function() { return CubicInterpolant; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interpolant", function() { return Interpolant; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Triangle", function() { return Triangle; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Math", function() { return _Math; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spherical", function() { return Spherical; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cylindrical", function() { return Cylindrical; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Plane", function() { return Plane; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Frustum", function() { return Frustum; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sphere", function() { return Sphere; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Ray", function() { return Ray; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix4", function() { return Matrix4; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix3", function() { return Matrix3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3", function() { return Box3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box2", function() { return Box2; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line3", function() { return Line3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Euler", function() { return Euler; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector4", function() { return Vector4; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3", function() { return Vector3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2", function() { return Vector2; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Quaternion", function() { return Quaternion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MorphBlendMesh", function() { return MorphBlendMesh; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImmediateRenderObject", function() { return ImmediateRenderObject; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexNormalsHelper", function() { return VertexNormalsHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightHelper", function() { return SpotLightHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkeletonHelper", function() { return SkeletonHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLightHelper", function() { return PointLightHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLightHelper", function() { return RectAreaLightHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLightHelper", function() { return HemisphereLightHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GridHelper", function() { return GridHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolarGridHelper", function() { return PolarGridHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceNormalsHelper", function() { return FaceNormalsHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightHelper", function() { return DirectionalLightHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CameraHelper", function() { return CameraHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxHelper", function() { return BoxHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrowHelper", function() { return ArrowHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxisHelper", function() { return AxisHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CatmullRomCurve3", function() { return CatmullRomCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve3", function() { return CubicBezierCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve3", function() { return QuadraticBezierCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve3", function() { return LineCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArcCurve", function() { return ArcCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EllipseCurve", function() { return EllipseCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve", function() { return SplineCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve", function() { return CubicBezierCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve", function() { return QuadraticBezierCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve", function() { return LineCurve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Shape", function() { return Shape; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Path", function() { return Path; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapePath", function() { return ShapePath; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Font", function() { return Font; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CurvePath", function() { return CurvePath; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Curve", function() { return Curve; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeUtils", function() { return ShapeUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SceneUtils", function() { return SceneUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeGeometry", function() { return WireframeGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricGeometry", function() { return ParametricGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricBufferGeometry", function() { return ParametricBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronGeometry", function() { return TetrahedronGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronBufferGeometry", function() { return TetrahedronBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronGeometry", function() { return OctahedronGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronBufferGeometry", function() { return OctahedronBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronGeometry", function() { return IcosahedronGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronBufferGeometry", function() { return IcosahedronBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronGeometry", function() { return DodecahedronGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronBufferGeometry", function() { return DodecahedronBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronGeometry", function() { return PolyhedronGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronBufferGeometry", function() { return PolyhedronBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeGeometry", function() { return TubeGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeBufferGeometry", function() { return TubeBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotGeometry", function() { return TorusKnotGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotBufferGeometry", function() { return TorusKnotBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusGeometry", function() { return TorusGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusBufferGeometry", function() { return TorusBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextGeometry", function() { return TextGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBufferGeometry", function() { return TextBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereGeometry", function() { return SphereGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereBufferGeometry", function() { return SphereBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingGeometry", function() { return RingGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingBufferGeometry", function() { return RingBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneGeometry", function() { return PlaneGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneBufferGeometry", function() { return PlaneBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheGeometry", function() { return LatheGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheBufferGeometry", function() { return LatheBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeGeometry", function() { return ShapeGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeBufferGeometry", function() { return ShapeBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeGeometry", function() { return ExtrudeGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeBufferGeometry", function() { return ExtrudeBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesGeometry", function() { return EdgesGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeGeometry", function() { return ConeGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeBufferGeometry", function() { return ConeBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderGeometry", function() { return CylinderGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderBufferGeometry", function() { return CylinderBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleGeometry", function() { return CircleGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleBufferGeometry", function() { return CircleBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxGeometry", function() { return BoxGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxBufferGeometry", function() { return BoxBufferGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShadowMaterial", function() { return ShadowMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpriteMaterial", function() { return SpriteMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RawShaderMaterial", function() { return RawShaderMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderMaterial", function() { return ShaderMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointsMaterial", function() { return PointsMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhysicalMaterial", function() { return MeshPhysicalMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshStandardMaterial", function() { return MeshStandardMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhongMaterial", function() { return MeshPhongMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshToonMaterial", function() { return MeshToonMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshNormalMaterial", function() { return MeshNormalMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshLambertMaterial", function() { return MeshLambertMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDepthMaterial", function() { return MeshDepthMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshBasicMaterial", function() { return MeshBasicMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineDashedMaterial", function() { return LineDashedMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineBasicMaterial", function() { return LineBasicMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Material", function() { return Material; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64BufferAttribute", function() { return Float64BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32BufferAttribute", function() { return Float32BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32BufferAttribute", function() { return Uint32BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32BufferAttribute", function() { return Int32BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16BufferAttribute", function() { return Uint16BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16BufferAttribute", function() { return Int16BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedBufferAttribute", function() { return Uint8ClampedBufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8BufferAttribute", function() { return Uint8BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8BufferAttribute", function() { return Int8BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferAttribute", function() { return BufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "REVISION", function() { return REVISION; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MOUSE", function() { return MOUSE; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceNone", function() { return CullFaceNone; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceBack", function() { return CullFaceBack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFront", function() { return CullFaceFront; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFrontBack", function() { return CullFaceFrontBack; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCW", function() { return FrontFaceDirectionCW; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCCW", function() { return FrontFaceDirectionCCW; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicShadowMap", function() { return BasicShadowMap; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFShadowMap", function() { return PCFShadowMap; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFSoftShadowMap", function() { return PCFSoftShadowMap; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontSide", function() { return FrontSide; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BackSide", function() { return BackSide; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DoubleSide", function() { return DoubleSide; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FlatShading", function() { return FlatShading; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SmoothShading", function() { return SmoothShading; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoColors", function() { return NoColors; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceColors", function() { return FaceColors; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexColors", function() { return VertexColors; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoBlending", function() { return NoBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NormalBlending", function() { return NormalBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdditiveBlending", function() { return AdditiveBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractiveBlending", function() { return SubtractiveBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyBlending", function() { return MultiplyBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CustomBlending", function() { return CustomBlending; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddEquation", function() { return AddEquation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractEquation", function() { return SubtractEquation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReverseSubtractEquation", function() { return ReverseSubtractEquation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MinEquation", function() { return MinEquation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaxEquation", function() { return MaxEquation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroFactor", function() { return ZeroFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneFactor", function() { return OneFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcColorFactor", function() { return SrcColorFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcColorFactor", function() { return OneMinusSrcColorFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaFactor", function() { return SrcAlphaFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcAlphaFactor", function() { return OneMinusSrcAlphaFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstAlphaFactor", function() { return DstAlphaFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstAlphaFactor", function() { return OneMinusDstAlphaFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstColorFactor", function() { return DstColorFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstColorFactor", function() { return OneMinusDstColorFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaSaturateFactor", function() { return SrcAlphaSaturateFactor; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NeverDepth", function() { return NeverDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlwaysDepth", function() { return AlwaysDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessDepth", function() { return LessDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessEqualDepth", function() { return LessEqualDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EqualDepth", function() { return EqualDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterEqualDepth", function() { return GreaterEqualDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterDepth", function() { return GreaterDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NotEqualDepth", function() { return NotEqualDepth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyOperation", function() { return MultiplyOperation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MixOperation", function() { return MixOperation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddOperation", function() { return AddOperation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoToneMapping", function() { return NoToneMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearToneMapping", function() { return LinearToneMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReinhardToneMapping", function() { return ReinhardToneMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uncharted2ToneMapping", function() { return Uncharted2ToneMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CineonToneMapping", function() { return CineonToneMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UVMapping", function() { return UVMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeReflectionMapping", function() { return CubeReflectionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeRefractionMapping", function() { return CubeRefractionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularReflectionMapping", function() { return EquirectangularReflectionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularRefractionMapping", function() { return EquirectangularRefractionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphericalReflectionMapping", function() { return SphericalReflectionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVReflectionMapping", function() { return CubeUVReflectionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVRefractionMapping", function() { return CubeUVRefractionMapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RepeatWrapping", function() { return RepeatWrapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClampToEdgeWrapping", function() { return ClampToEdgeWrapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MirroredRepeatWrapping", function() { return MirroredRepeatWrapping; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestFilter", function() { return NearestFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapNearestFilter", function() { return NearestMipMapNearestFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapLinearFilter", function() { return NearestMipMapLinearFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearFilter", function() { return LinearFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapNearestFilter", function() { return LinearMipMapNearestFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapLinearFilter", function() { return LinearMipMapLinearFilter; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedByteType", function() { return UnsignedByteType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteType", function() { return ByteType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShortType", function() { return ShortType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShortType", function() { return UnsignedShortType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IntType", function() { return IntType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedIntType", function() { return UnsignedIntType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatType", function() { return FloatType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HalfFloatType", function() { return HalfFloatType; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort4444Type", function() { return UnsignedShort4444Type; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort5551Type", function() { return UnsignedShort5551Type; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort565Type", function() { return UnsignedShort565Type; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedInt248Type", function() { return UnsignedInt248Type; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlphaFormat", function() { return AlphaFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBFormat", function() { return RGBFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBAFormat", function() { return RGBAFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceFormat", function() { return LuminanceFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceAlphaFormat", function() { return LuminanceAlphaFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEFormat", function() { return RGBEFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthFormat", function() { return DepthFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthStencilFormat", function() { return DepthStencilFormat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_S3TC_DXT1_Format", function() { return RGB_S3TC_DXT1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT1_Format", function() { return RGBA_S3TC_DXT1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT3_Format", function() { return RGBA_S3TC_DXT3_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT5_Format", function() { return RGBA_S3TC_DXT5_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_4BPPV1_Format", function() { return RGB_PVRTC_4BPPV1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_2BPPV1_Format", function() { return RGB_PVRTC_2BPPV1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_4BPPV1_Format", function() { return RGBA_PVRTC_4BPPV1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_2BPPV1_Format", function() { return RGBA_PVRTC_2BPPV1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_ETC1_Format", function() { return RGB_ETC1_Format; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopOnce", function() { return LoopOnce; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopRepeat", function() { return LoopRepeat; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopPingPong", function() { return LoopPingPong; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateDiscrete", function() { return InterpolateDiscrete; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateLinear", function() { return InterpolateLinear; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateSmooth", function() { return InterpolateSmooth; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroCurvatureEnding", function() { return ZeroCurvatureEnding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroSlopeEnding", function() { return ZeroSlopeEnding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WrapAroundEnding", function() { return WrapAroundEnding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TrianglesDrawMode", function() { return TrianglesDrawMode; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleStripDrawMode", function() { return TriangleStripDrawMode; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleFanDrawMode", function() { return TriangleFanDrawMode; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearEncoding", function() { return LinearEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sRGBEncoding", function() { return sRGBEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GammaEncoding", function() { return GammaEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEEncoding", function() { return RGBEEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LogLuvEncoding", function() { return LogLuvEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM7Encoding", function() { return RGBM7Encoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM16Encoding", function() { return RGBM16Encoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBDEncoding", function() { return RGBDEncoding; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicDepthPacking", function() { return BasicDepthPacking; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBADepthPacking", function() { return RGBADepthPacking; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeGeometry", function() { return BoxGeometry; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face4", function() { return Face4; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineStrip", function() { return LineStrip; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinePieces", function() { return LinePieces; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshFaceMaterial", function() { return MeshFaceMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiMaterial", function() { return MultiMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloud", function() { return PointCloud; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Particle", function() { return Particle; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystem", function() { return ParticleSystem; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloudMaterial", function() { return PointCloudMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleBasicMaterial", function() { return ParticleBasicMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystemMaterial", function() { return ParticleSystemMaterial; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vertex", function() { return Vertex; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DynamicBufferAttribute", function() { return DynamicBufferAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8Attribute", function() { return Int8Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8Attribute", function() { return Uint8Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedAttribute", function() { return Uint8ClampedAttribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16Attribute", function() { return Int16Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16Attribute", function() { return Uint16Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32Attribute", function() { return Int32Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32Attribute", function() { return Uint32Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32Attribute", function() { return Float32Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64Attribute", function() { return Float64Attribute; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClosedSplineCurve3", function() { return ClosedSplineCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve3", function() { return SplineCurve3; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spline", function() { return Spline; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoundingBoxHelper", function() { return BoundingBoxHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesHelper", function() { return EdgesHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeHelper", function() { return WireframeHelper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XHRLoader", function() { return XHRLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BinaryTextureLoader", function() { return BinaryTextureLoader; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryUtils", function() { return GeometryUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageUtils", function() { return ImageUtils; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Projector", function() { return Projector; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasRenderer", function() { return CanvasRenderer; });
// Polyfills

if ( Number.EPSILON === undefined ) {

    Number.EPSILON = Math.pow( 2, - 52 );

}

if ( Number.isInteger === undefined ) {

    // Missing in IE
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger

    Number.isInteger = function ( value ) {

        return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;

    };

}

//

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;

    };

}

if ( Function.prototype.name === undefined ) {

    // Missing in IE
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

    Object.defineProperty( Function.prototype, 'name', {

        get: function () {

            return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];

        }

    } );

}

if ( Object.assign === undefined ) {

    // Missing in IE
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

    ( function () {

        Object.assign = function ( target ) {

            'use strict';

            if ( target === undefined || target === null ) {

                throw new TypeError( 'Cannot convert undefined or null to object' );

            }

            var output = Object( target );

            for ( var index = 1; index < arguments.length; index ++ ) {

                var source = arguments[ index ];

                if ( source !== undefined && source !== null ) {

                    for ( var nextKey in source ) {

                        if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {

                            output[ nextKey ] = source[ nextKey ];

                        }

                    }

                }

            }

            return output;

        };

    } )();

}

/**
 * https://github.com/mrdoob/eventdispatcher.js/
 */

function EventDispatcher() {}

Object.assign( EventDispatcher.prototype, {

    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;

        return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;

    },

    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 = listenerArray.slice( 0 );

            for ( var i = 0, l = array.length; i < l; i ++ ) {

                array[ i ].call( this, event );

            }

        }

    }

} );

var REVISION = '86';
var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
var CullFaceNone = 0;
var CullFaceBack = 1;
var CullFaceFront = 2;
var CullFaceFrontBack = 3;
var FrontFaceDirectionCW = 0;
var FrontFaceDirectionCCW = 1;
var BasicShadowMap = 0;
var PCFShadowMap = 1;
var PCFSoftShadowMap = 2;
var FrontSide = 0;
var BackSide = 1;
var DoubleSide = 2;
var FlatShading = 1;
var SmoothShading = 2;
var NoColors = 0;
var FaceColors = 1;
var VertexColors = 2;
var NoBlending = 0;
var NormalBlending = 1;
var AdditiveBlending = 2;
var SubtractiveBlending = 3;
var MultiplyBlending = 4;
var CustomBlending = 5;
var AddEquation = 100;
var SubtractEquation = 101;
var ReverseSubtractEquation = 102;
var MinEquation = 103;
var MaxEquation = 104;
var ZeroFactor = 200;
var OneFactor = 201;
var SrcColorFactor = 202;
var OneMinusSrcColorFactor = 203;
var SrcAlphaFactor = 204;
var OneMinusSrcAlphaFactor = 205;
var DstAlphaFactor = 206;
var OneMinusDstAlphaFactor = 207;
var DstColorFactor = 208;
var OneMinusDstColorFactor = 209;
var SrcAlphaSaturateFactor = 210;
var NeverDepth = 0;
var AlwaysDepth = 1;
var LessDepth = 2;
var LessEqualDepth = 3;
var EqualDepth = 4;
var GreaterEqualDepth = 5;
var GreaterDepth = 6;
var NotEqualDepth = 7;
var MultiplyOperation = 0;
var MixOperation = 1;
var AddOperation = 2;
var NoToneMapping = 0;
var LinearToneMapping = 1;
var ReinhardToneMapping = 2;
var Uncharted2ToneMapping = 3;
var CineonToneMapping = 4;
var UVMapping = 300;
var CubeReflectionMapping = 301;
var CubeRefractionMapping = 302;
var EquirectangularReflectionMapping = 303;
var EquirectangularRefractionMapping = 304;
var SphericalReflectionMapping = 305;
var CubeUVReflectionMapping = 306;
var CubeUVRefractionMapping = 307;
var RepeatWrapping = 1000;
var ClampToEdgeWrapping = 1001;
var MirroredRepeatWrapping = 1002;
var NearestFilter = 1003;
var NearestMipMapNearestFilter = 1004;
var NearestMipMapLinearFilter = 1005;
var LinearFilter = 1006;
var LinearMipMapNearestFilter = 1007;
var LinearMipMapLinearFilter = 1008;
var UnsignedByteType = 1009;
var ByteType = 1010;
var ShortType = 1011;
var UnsignedShortType = 1012;
var IntType = 1013;
var UnsignedIntType = 1014;
var FloatType = 1015;
var HalfFloatType = 1016;
var UnsignedShort4444Type = 1017;
var UnsignedShort5551Type = 1018;
var UnsignedShort565Type = 1019;
var UnsignedInt248Type = 1020;
var AlphaFormat = 1021;
var RGBFormat = 1022;
var RGBAFormat = 1023;
var LuminanceFormat = 1024;
var LuminanceAlphaFormat = 1025;
var RGBEFormat = RGBAFormat;
var DepthFormat = 1026;
var DepthStencilFormat = 1027;
var RGB_S3TC_DXT1_Format = 2001;
var RGBA_S3TC_DXT1_Format = 2002;
var RGBA_S3TC_DXT3_Format = 2003;
var RGBA_S3TC_DXT5_Format = 2004;
var RGB_PVRTC_4BPPV1_Format = 2100;
var RGB_PVRTC_2BPPV1_Format = 2101;
var RGBA_PVRTC_4BPPV1_Format = 2102;
var RGBA_PVRTC_2BPPV1_Format = 2103;
var RGB_ETC1_Format = 2151;
var LoopOnce = 2200;
var LoopRepeat = 2201;
var LoopPingPong = 2202;
var InterpolateDiscrete = 2300;
var InterpolateLinear = 2301;
var InterpolateSmooth = 2302;
var ZeroCurvatureEnding = 2400;
var ZeroSlopeEnding = 2401;
var WrapAroundEnding = 2402;
var TrianglesDrawMode = 0;
var TriangleStripDrawMode = 1;
var TriangleFanDrawMode = 2;
var LinearEncoding = 3000;
var sRGBEncoding = 3001;
var GammaEncoding = 3007;
var RGBEEncoding = 3002;
var LogLuvEncoding = 3003;
var RGBM7Encoding = 3004;
var RGBM16Encoding = 3005;
var RGBDEncoding = 3006;
var BasicDepthPacking = 3200;
var RGBADepthPacking = 3201;

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

var _Math = {

    DEG2RAD: Math.PI / 180,
    RAD2DEG: 180 / Math.PI,

    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 generateUUID() {

            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: function ( value, min, max ) {

        return Math.max( min, Math.min( max, value ) );

    },

    // compute euclidian modulo of m % n
    // https://en.wikipedia.org/wiki/Modulo_operation

    euclideanModulo: function ( n, m ) {

        return ( ( n % m ) + m ) % m;

    },

    // 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 );

    },

    // https://en.wikipedia.org/wiki/Linear_interpolation

    lerp: function ( x, y, t ) {

        return ( 1 - t ) * x + t * y;

    },

    // 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 integer from <low, high> interval

    randInt: function ( low, high ) {

        return low + Math.floor( Math.random() * ( high - low + 1 ) );

    },

    // Random float from <low, high> interval

    randFloat: function ( low, high ) {

        return low + Math.random() * ( high - low );

    },

    // Random float from <-range/2, range/2> interval

    randFloatSpread: function ( range ) {

        return range * ( 0.5 - Math.random() );

    },

    degToRad: function ( degrees ) {

        return degrees * _Math.DEG2RAD;

    },

    radToDeg: function ( radians ) {

        return radians * _Math.RAD2DEG;

    },

    isPowerOfTwo: function ( value ) {

        return ( value & ( value - 1 ) ) === 0 && value !== 0;

    },

    nearestPowerOfTwo: function ( value ) {

        return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );

    },

    nextPowerOfTwo: function ( value ) {

        value --;
        value |= value >> 1;
        value |= value >> 2;
        value |= value >> 4;
        value |= value >> 8;
        value |= value >> 16;
        value ++;

        return value;

    }

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author philogb / http://blog.thejit.org/
 * @author egraether / http://egraether.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 */

function Vector2( x, y ) {

    this.x = x || 0;
    this.y = y || 0;

}

Object.defineProperties( Vector2.prototype, {

    "width" : {

        get: function () {

            return this.x;

        },

        set: function ( value ) {

            this.x = value;

        }

    },

    "height" : {

        get: function () {

            return this.y;

        },

        set: function ( value ) {

            this.y = value;

        }

    }

} );

Object.assign( Vector2.prototype, {

    isVector2: true,

    set: function ( x, y ) {

        this.x = x;
        this.y = y;

        return this;

    },

    setScalar: function ( scalar ) {

        this.x = scalar;
        this.y = scalar;

        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 );

        }

        return this;

    },

    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 );

        }

    },

    clone: function () {

        return new this.constructor( this.x, this.y );

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;

        return this;

    },

    add: function ( v, w ) {

        if ( w !== undefined ) {

            console.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;

    },

    addScaledVector: function ( v, s ) {

        this.x += v.x * s;
        this.y += v.y * s;

        return this;

    },

    sub: function ( v, w ) {

        if ( w !== undefined ) {

            console.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 ( scalar ) {

        this.x *= scalar;
        this.y *= scalar;

        return this;

    },

    divide: function ( v ) {

        this.x /= v.x;
        this.y /= v.y;

        return this;

    },

    divideScalar: function ( scalar ) {

        return this.multiplyScalar( 1 / scalar );

    },

    min: function ( v ) {

        this.x = Math.min( this.x, v.x );
        this.y = Math.min( this.y, v.y );

        return this;

    },

    max: function ( v ) {

        this.x = Math.max( this.x, v.x );
        this.y = Math.max( this.y, v.y );

        return this;

    },

    clamp: function ( min, max ) {

        // assumes min < max, componentwise

        this.x = Math.max( min.x, Math.min( max.x, this.x ) );
        this.y = Math.max( min.y, Math.min( max.y, this.y ) );

        return this;

    },

    clampScalar: function () {

        var min = new Vector2();
        var max = new Vector2();

        return function clampScalar( minVal, maxVal ) {

            min.set( minVal, minVal );
            max.set( maxVal, maxVal );

            return this.clamp( min, max );

        };

    }(),

    clampLength: function ( min, max ) {

        var length = this.length();

        return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );

    },

    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 );

    },

    lengthManhattan: function() {

        return Math.abs( this.x ) + Math.abs( this.y );

    },

    normalize: function () {

        return this.divideScalar( this.length() || 1 );

    },

    angle: function () {

        // computes the angle in radians with respect to the positive x-axis

        var angle = Math.atan2( this.y, this.x );

        if ( angle < 0 ) angle += 2 * Math.PI;

        return angle;

    },

    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;

    },

    distanceToManhattan: function ( v ) {

        return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );

    },

    setLength: function ( length ) {

        return this.normalize().multiplyScalar( length );

    },

    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 ) {

        return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

    },

    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;

    },

    fromBufferAttribute: function ( attribute, index, offset ) {

        if ( offset !== undefined ) {

            console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );

        }

        this.x = attribute.getX( index );
        this.y = attribute.getY( index );

        return this;

    },

    rotateAround: function ( center, angle ) {

        var c = Math.cos( angle ), s = Math.sin( angle );

        var x = this.x - center.x;
        var y = this.y - center.y;

        this.x = x * c - y * s + center.x;
        this.y = x * s + y * c + center.y;

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author szimek / https://github.com/szimek/
 */

var textureId = 0;

function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {

    Object.defineProperty( this, 'id', { value: textureId ++ } );

    this.uuid = _Math.generateUUID();

    this.name = '';

    this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
    this.mipmaps = [];

    this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;

    this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
    this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;

    this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
    this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;

    this.anisotropy = anisotropy !== undefined ? anisotropy : 1;

    this.format = format !== undefined ? format : RGBAFormat;
    this.type = type !== undefined ? type : UnsignedByteType;

    this.offset = new Vector2( 0, 0 );
    this.repeat = new 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)

    // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
    //
    // Also changing the encoding after already used by a Material will not automatically make the Material
    // update.  You need to explicitly call Material.needsUpdate to trigger it to recompile.
    this.encoding = encoding !== undefined ? encoding : LinearEncoding;

    this.version = 0;
    this.onUpdate = null;

}

Texture.DEFAULT_IMAGE = undefined;
Texture.DEFAULT_MAPPING = UVMapping;

Object.defineProperty( Texture.prototype, "needsUpdate", {

    set: function ( value ) {

        if ( value === true ) this.version ++;

    }

} );

Object.assign( Texture.prototype, EventDispatcher.prototype, {

    constructor: Texture,

    isTexture: true,

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( source ) {

        this.name = source.name;

        this.image = source.image;
        this.mipmaps = source.mipmaps.slice( 0 );

        this.mapping = source.mapping;

        this.wrapS = source.wrapS;
        this.wrapT = source.wrapT;

        this.magFilter = source.magFilter;
        this.minFilter = source.minFilter;

        this.anisotropy = source.anisotropy;

        this.format = source.format;
        this.type = source.type;

        this.offset.copy( source.offset );
        this.repeat.copy( source.repeat );

        this.generateMipmaps = source.generateMipmaps;
        this.premultiplyAlpha = source.premultiplyAlpha;
        this.flipY = source.flipY;
        this.unpackAlignment = source.unpackAlignment;
        this.encoding = source.encoding;

        return this;

    },

    toJSON: function ( meta ) {

        if ( meta.textures[ this.uuid ] !== undefined ) {

            return meta.textures[ this.uuid ];

        }

        function getDataURL( image ) {

            var canvas;

            if ( image.toDataURL !== undefined ) {

                canvas = image;

            } else {

                canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
                canvas.width = image.width;
                canvas.height = image.height;

                canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );

            }

            if ( canvas.width > 2048 || canvas.height > 2048 ) {

                return canvas.toDataURL( 'image/jpeg', 0.6 );

            } else {

                return canvas.toDataURL( 'image/png' );

            }

        }

        var output = {
            metadata: {
                version: 4.5,
                type: 'Texture',
                generator: 'Texture.toJSON'
            },

            uuid: this.uuid,
            name: this.name,

            mapping: this.mapping,

            repeat: [ this.repeat.x, this.repeat.y ],
            offset: [ this.offset.x, this.offset.y ],
            wrap: [ this.wrapS, this.wrapT ],

            minFilter: this.minFilter,
            magFilter: this.magFilter,
            anisotropy: this.anisotropy,

            flipY: this.flipY
        };

        if ( this.image !== undefined ) {

            // TODO: Move to THREE.Image

            var image = this.image;

            if ( image.uuid === undefined ) {

                image.uuid = _Math.generateUUID(); // UGH

            }

            if ( meta.images[ image.uuid ] === undefined ) {

                meta.images[ image.uuid ] = {
                    uuid: image.uuid,
                    url: getDataURL( image )
                };

            }

            output.image = image.uuid;

        }

        meta.textures[ this.uuid ] = output;

        return output;

    },

    dispose: function () {

        this.dispatchEvent( { type: 'dispose' } );

    },

    transformUv: function ( uv ) {

        if ( this.mapping !== UVMapping ) return;

        uv.multiply( this.repeat );
        uv.add( this.offset );

        if ( uv.x < 0 || uv.x > 1 ) {

            switch ( this.wrapS ) {

                case RepeatWrapping:

                    uv.x = uv.x - Math.floor( uv.x );
                    break;

                case ClampToEdgeWrapping:

                    uv.x = uv.x < 0 ? 0 : 1;
                    break;

                case MirroredRepeatWrapping:

                    if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {

                        uv.x = Math.ceil( uv.x ) - uv.x;

                    } else {

                        uv.x = uv.x - Math.floor( uv.x );

                    }
                    break;

            }

        }

        if ( uv.y < 0 || uv.y > 1 ) {

            switch ( this.wrapT ) {

                case RepeatWrapping:

                    uv.y = uv.y - Math.floor( uv.y );
                    break;

                case ClampToEdgeWrapping:

                    uv.y = uv.y < 0 ? 0 : 1;
                    break;

                case MirroredRepeatWrapping:

                    if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {

                        uv.y = Math.ceil( uv.y ) - uv.y;

                    } else {

                        uv.y = uv.y - Math.floor( uv.y );

                    }
                    break;

            }

        }

        if ( this.flipY ) {

            uv.y = 1 - uv.y;

        }

    }

} );

/**
 * @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
 */

function Vector4( x, y, z, w ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
    this.w = ( w !== undefined ) ? w : 1;

}

Object.assign( Vector4.prototype, {

    isVector4: true,

    set: function ( x, y, z, w ) {

        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;

        return this;

    },

    setScalar: function ( scalar ) {

        this.x = scalar;
        this.y = scalar;
        this.z = scalar;
        this.w = scalar;

        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 );

        }

        return this;

    },

    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 );

        }

    },

    clone: function () {

        return new this.constructor( this.x, this.y, this.z, this.w );

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;
        this.z = v.z;
        this.w = ( v.w !== undefined ) ? v.w : 1;

        return this;

    },

    add: function ( v, w ) {

        if ( w !== undefined ) {

            console.warn( '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;

    },

    addScaledVector: function ( v, s ) {

        this.x += v.x * s;
        this.y += v.y * s;
        this.z += v.z * s;
        this.w += v.w * s;

        return this;

    },

    sub: function ( v, w ) {

        if ( w !== undefined ) {

            console.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, y = this.y, z = this.z, 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 ) {

        return this.multiplyScalar( 1 / scalar );

    },

    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 ) {

        this.x = Math.min( this.x, v.x );
        this.y = Math.min( this.y, v.y );
        this.z = Math.min( this.z, v.z );
        this.w = Math.min( this.w, v.w );

        return this;

    },

    max: function ( v ) {

        this.x = Math.max( this.x, v.x );
        this.y = Math.max( this.y, v.y );
        this.z = Math.max( this.z, v.z );
        this.w = Math.max( this.w, v.w );

        return this;

    },

    clamp: function ( min, max ) {

        // assumes min < max, componentwise

        this.x = Math.max( min.x, Math.min( max.x, this.x ) );
        this.y = Math.max( min.y, Math.min( max.y, this.y ) );
        this.z = Math.max( min.z, Math.min( max.z, this.z ) );
        this.w = Math.max( min.w, Math.min( max.w, this.w ) );

        return this;

    },

    clampScalar: function () {

        var min, max;

        return function clampScalar( minVal, maxVal ) {

            if ( min === undefined ) {

                min = new Vector4();
                max = new Vector4();

            }

            min.set( minVal, minVal, minVal, minVal );
            max.set( maxVal, maxVal, maxVal, maxVal );

            return this.clamp( min, max );

        };

    }(),

    clampLength: function ( min, max ) {

        var length = this.length();

        return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );

    },

    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() || 1 );

    },

    setLength: function ( length ) {

        return this.normalize().multiplyScalar( length );

    },

    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 ) {

        return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

    },

    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;

    },

    fromBufferAttribute: function ( attribute, index, offset ) {

        if ( offset !== undefined ) {

            console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );

        }

        this.x = attribute.getX( index );
        this.y = attribute.getY( index );
        this.z = attribute.getZ( index );
        this.w = attribute.getW( index );

        return this;

    }

} );

/**
 * @author szimek / https://github.com/szimek/
 * @author alteredq / http://alteredqualia.com/
 * @author Marius Kintel / https://github.com/kintel
 */

/*
 In options, we can specify:
 * Texture parameters for an auto-generated target texture
 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
*/
function WebGLRenderTarget( width, height, options ) {

    this.uuid = _Math.generateUUID();

    this.width = width;
    this.height = height;

    this.scissor = new Vector4( 0, 0, width, height );
    this.scissorTest = false;

    this.viewport = new Vector4( 0, 0, width, height );

    options = options || {};

    if ( options.minFilter === undefined ) options.minFilter = LinearFilter;

    this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );

    this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
    this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
    this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;

}

Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, {

    isWebGLRenderTarget: true,

    setSize: function ( width, height ) {

        if ( this.width !== width || this.height !== height ) {

            this.width = width;
            this.height = height;

            this.dispose();

        }

        this.viewport.set( 0, 0, width, height );
        this.scissor.set( 0, 0, width, height );

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( source ) {

        this.width = source.width;
        this.height = source.height;

        this.viewport.copy( source.viewport );

        this.texture = source.texture.clone();

        this.depthBuffer = source.depthBuffer;
        this.stencilBuffer = source.stencilBuffer;
        this.depthTexture = source.depthTexture;

        return this;

    },

    dispose: function () {

        this.dispatchEvent( { type: 'dispose' } );

    }

} );

/**
 * @author alteredq / http://alteredqualia.com
 */

function WebGLRenderTargetCube( width, height, options ) {

    WebGLRenderTarget.call( this, width, height, options );

    this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
    this.activeMipMapLevel = 0;

}

WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;

WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://clara.io
 */

function Quaternion( x, y, z, w ) {

    this._x = x || 0;
    this._y = y || 0;
    this._z = z || 0;
    this._w = ( w !== undefined ) ? w : 1;

}

Object.assign( Quaternion, {

    slerp: function ( qa, qb, qm, t ) {

        return qm.copy( qa ).slerp( qb, t );

    },

    slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {

        // fuzz-free, array-based Quaternion SLERP operation

        var x0 = src0[ srcOffset0 + 0 ],
            y0 = src0[ srcOffset0 + 1 ],
            z0 = src0[ srcOffset0 + 2 ],
            w0 = src0[ srcOffset0 + 3 ],

            x1 = src1[ srcOffset1 + 0 ],
            y1 = src1[ srcOffset1 + 1 ],
            z1 = src1[ srcOffset1 + 2 ],
            w1 = src1[ srcOffset1 + 3 ];

        if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {

            var s = 1 - t,

                cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,

                dir = ( cos >= 0 ? 1 : - 1 ),
                sqrSin = 1 - cos * cos;

            // Skip the Slerp for tiny steps to avoid numeric problems:
            if ( sqrSin > Number.EPSILON ) {

                var sin = Math.sqrt( sqrSin ),
                    len = Math.atan2( sin, cos * dir );

                s = Math.sin( s * len ) / sin;
                t = Math.sin( t * len ) / sin;

            }

            var tDir = t * dir;

            x0 = x0 * s + x1 * tDir;
            y0 = y0 * s + y1 * tDir;
            z0 = z0 * s + z1 * tDir;
            w0 = w0 * s + w1 * tDir;

            // Normalize in case we just did a lerp:
            if ( s === 1 - t ) {

                var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );

                x0 *= f;
                y0 *= f;
                z0 *= f;
                w0 *= f;

            }

        }

        dst[ dstOffset ] = x0;
        dst[ dstOffset + 1 ] = y0;
        dst[ dstOffset + 2 ] = z0;
        dst[ dstOffset + 3 ] = w0;

    }

} );

Object.defineProperties( Quaternion.prototype, {

    x: {

        get: function () {

            return this._x;

        },

        set: function ( value ) {

            this._x = value;
            this.onChangeCallback();

        }

    },

    y: {

        get: function () {

            return this._y;

        },

        set: function ( value ) {

            this._y = value;
            this.onChangeCallback();

        }

    },

    z: {

        get: function () {

            return this._z;

        },

        set: function ( value ) {

            this._z = value;
            this.onChangeCallback();

        }

    },

    w: {

        get: function () {

            return this._w;

        },

        set: function ( value ) {

            this._w = value;
            this.onChangeCallback();

        }

    }

} );

Object.assign( Quaternion.prototype, {

    set: function ( x, y, z, w ) {

        this._x = x;
        this._y = y;
        this._z = z;
        this._w = w;

        this.onChangeCallback();

        return this;

    },

    clone: function () {

        return new this.constructor( this._x, this._y, this._z, this._w );

    },

    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 && euler.isEuler ) ) {

            throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );

        }

        var x = euler._x, y = euler._y, z = euler._z, order = euler.order;

        // http://www.mathworks.com/matlabcentral/fileexchange/
        //     20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
        //    content/SpinCalc.m

        var cos = Math.cos;
        var sin = Math.sin;

        var c1 = cos( x / 2 );
        var c2 = cos( y / 2 );
        var c3 = cos( z / 2 );

        var s1 = sin( x / 2 );
        var s2 = sin( y / 2 );
        var s3 = sin( z / 2 );

        if ( order === 'XYZ' ) {

            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'YXZ' ) {

            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;

        } else if ( order === 'ZXY' ) {

            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'ZYX' ) {

            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;

        } else if ( order === 'YZX' ) {

            this._x = s1 * c2 * c3 + c1 * s2 * s3;
            this._y = c1 * s2 * c3 + s1 * c2 * s3;
            this._z = c1 * c2 * s3 - s1 * s2 * c3;
            this._w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'XZY' ) {

            this._x = s1 * c2 * c3 - c1 * s2 * s3;
            this._y = c1 * s2 * c3 - s1 * c2 * s3;
            this._z = c1 * c2 * s3 + s1 * s2 * c3;
            this._w = c1 * c2 * c3 + s1 * s2 * s3;

        }

        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 () {

        // assumes direction vectors vFrom and vTo are normalized

        var v1 = new Vector3();
        var r;

        var EPS = 0.000001;

        return function setFromUnitVectors( vFrom, vTo ) {

            if ( v1 === undefined ) v1 = new 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;

            return this.normalize();

        };

    }(),

    inverse: function () {

        return this.conjugate().normalize();

    },

    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 ) {

            console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
            return this.multiplyQuaternions( q, p );

        }

        return this.multiplyQuaternions( this, q );

    },

    premultiply: function ( q ) {

        return this.multiplyQuaternions( q, this );

    },

    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;

    },

    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 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 halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
        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 () {}

} );

/**
 * @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
 */

function Vector3( x, y, z ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;

}

Object.assign( Vector3.prototype, {

    isVector3: true,

    set: function ( x, y, z ) {

        this.x = x;
        this.y = y;
        this.z = z;

        return this;

    },

    setScalar: function ( scalar ) {

        this.x = scalar;
        this.y = scalar;
        this.z = scalar;

        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 );

        }

        return this;

    },

    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 );

        }

    },

    clone: function () {

        return new this.constructor( this.x, this.y, this.z );

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;
        this.z = v.z;

        return this;

    },

    add: function ( v, w ) {

        if ( w !== undefined ) {

            console.warn( '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;

    },

    addScaledVector: function ( v, s ) {

        this.x += v.x * s;
        this.y += v.y * s;
        this.z += v.z * s;

        return this;

    },

    sub: function ( v, w ) {

        if ( w !== undefined ) {

            console.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 ) {

            console.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 = new Quaternion();

        return function applyEuler( euler ) {

            if ( ! ( euler && euler.isEuler ) ) {

                console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );

            }

            return this.applyQuaternion( quaternion.setFromEuler( euler ) );

        };

    }(),

    applyAxisAngle: function () {

        var quaternion = new Quaternion();

        return function applyAxisAngle( axis, angle ) {

            return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );

        };

    }(),

    applyMatrix3: function ( m ) {

        var x = this.x, y = this.y, 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 ) {

        var x = this.x, y = this.y, z = this.z;
        var e = m.elements;

        var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );

        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;

        return this;

    },

    applyQuaternion: function ( q ) {

        var x = this.x, y = this.y, z = this.z;
        var qx = q.x, qy = q.y, qz = q.z, 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 = new Matrix4();

        return function project( camera ) {

            matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
            return this.applyMatrix4( matrix );

        };

    }(),

    unproject: function () {

        var matrix = new Matrix4();

        return function unproject( camera ) {

            matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
            return this.applyMatrix4( 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;

        return this.normalize();

    },

    divide: function ( v ) {

        this.x /= v.x;
        this.y /= v.y;
        this.z /= v.z;

        return this;

    },

    divideScalar: function ( scalar ) {

        return this.multiplyScalar( 1 / scalar );

    },

    min: function ( v ) {

        this.x = Math.min( this.x, v.x );
        this.y = Math.min( this.y, v.y );
        this.z = Math.min( this.z, v.z );

        return this;

    },

    max: function ( v ) {

        this.x = Math.max( this.x, v.x );
        this.y = Math.max( this.y, v.y );
        this.z = Math.max( this.z, v.z );

        return this;

    },

    clamp: function ( min, max ) {

        // assumes min < max, componentwise

        this.x = Math.max( min.x, Math.min( max.x, this.x ) );
        this.y = Math.max( min.y, Math.min( max.y, this.y ) );
        this.z = Math.max( min.z, Math.min( max.z, this.z ) );

        return this;

    },

    clampScalar: function () {

        var min = new Vector3();
        var max = new Vector3();

        return function clampScalar( minVal, maxVal ) {

            min.set( minVal, minVal, minVal );
            max.set( maxVal, maxVal, maxVal );

            return this.clamp( min, max );

        };

    }(),

    clampLength: function ( min, max ) {

        var length = this.length();

        return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );

    },

    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;

    },

    // TODO lengthSquared?

    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() || 1 );

    },

    setLength: function ( length ) {

        return this.normalize().multiplyScalar( length );

    },

    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 ) {

        return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

    },

    cross: function ( v, w ) {

        if ( w !== undefined ) {

            console.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 ( vector ) {

        var scalar = vector.dot( this ) / vector.lengthSq();

        return this.copy( vector ).multiplyScalar( scalar );

    },

    projectOnPlane: function () {

        var v1 = new Vector3();

        return function projectOnPlane( planeNormal ) {

            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 = new Vector3();

        return function reflect( normal ) {

            return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );

        };

    }(),

    angleTo: function ( v ) {

        var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );

        // clamp, to handle numerical problems

        return Math.acos( _Math.clamp( theta, - 1, 1 ) );

    },

    distanceTo: function ( v ) {

        return Math.sqrt( this.distanceToSquared( v ) );

    },

    distanceToSquared: function ( v ) {

        var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;

        return dx * dx + dy * dy + dz * dz;

    },

    distanceToManhattan: function ( v ) {

        return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );

    },

    setFromSpherical: function ( s ) {

        var sinPhiRadius = Math.sin( s.phi ) * s.radius;

        this.x = sinPhiRadius * Math.sin( s.theta );
        this.y = Math.cos( s.phi ) * s.radius;
        this.z = sinPhiRadius * Math.cos( s.theta );

        return this;

    },

    setFromCylindrical: function ( c ) {

        this.x = c.radius * Math.sin( c.theta );
        this.y = c.y;
        this.z = c.radius * Math.cos( c.theta );

        return this;

    },

    setFromMatrixPosition: function ( m ) {

        var e = m.elements;

        this.x = e[ 12 ];
        this.y = e[ 13 ];
        this.z = e[ 14 ];

        return this;

    },

    setFromMatrixScale: function ( m ) {

        var sx = this.setFromMatrixColumn( m, 0 ).length();
        var sy = this.setFromMatrixColumn( m, 1 ).length();
        var sz = this.setFromMatrixColumn( m, 2 ).length();

        this.x = sx;
        this.y = sy;
        this.z = sz;

        return this;

    },

    setFromMatrixColumn: function ( m, index ) {

        return this.fromArray( m.elements, index * 4 );

    },

    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;

    },

    fromBufferAttribute: function ( attribute, index, offset ) {

        if ( offset !== undefined ) {

            console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );

        }

        this.x = attribute.getX( index );
        this.y = attribute.getY( index );
        this.z = attribute.getZ( index );

        return this;

    }

} );

/**
 * @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://clara.io
 * @author WestLangley / http://github.com/WestLangley
 */

function Matrix4() {

    this.elements = [

        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1

    ];

    if ( arguments.length > 0 ) {

        console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );

    }

}

Object.assign( Matrix4.prototype, {

    isMatrix4: true,

    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;

    },

    clone: function () {

        return new Matrix4().fromArray( this.elements );

    },

    copy: function ( m ) {

        var te = this.elements;
        var me = m.elements;

        te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
        te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
        te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
        te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];

        return this;

    },

    copyPosition: function ( m ) {

        var te = this.elements, me = m.elements;

        te[ 12 ] = me[ 12 ];
        te[ 13 ] = me[ 13 ];
        te[ 14 ] = me[ 14 ];

        return this;

    },

    extractBasis: function ( xAxis, yAxis, zAxis ) {

        xAxis.setFromMatrixColumn( this, 0 );
        yAxis.setFromMatrixColumn( this, 1 );
        zAxis.setFromMatrixColumn( this, 2 );

        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 Vector3();

        return function extractRotation( m ) {

            var te = this.elements;
            var me = m.elements;

            var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
            var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
            var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).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 && euler.isEuler ) ) {

            console.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;

    },

    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 Vector3();
        var y = new Vector3();
        var z = new Vector3();

        return function lookAt( eye, target, up ) {

            var te = this.elements;

            z.subVectors( eye, target );

            if ( z.lengthSq() === 0 ) {

                // eye and target are in the same position

                z.z = 1;

            }

            z.normalize();
            x.crossVectors( up, z );

            if ( x.lengthSq() === 0 ) {

                // up and z are parallel

                if ( Math.abs( up.z ) === 1 ) {

                    z.x += 0.0001;

                } else {

                    z.z += 0.0001;

                }

                z.normalize();
                x.crossVectors( up, z );

            }

            x.normalize();
            y.crossVectors( z, x );

            te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
            te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
            te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;

            return this;

        };

    }(),

    multiply: function ( m, n ) {

        if ( n !== undefined ) {

            console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
            return this.multiplyMatrices( m, n );

        }

        return this.multiplyMatrices( this, m );

    },

    premultiply: function ( m ) {

        return this.multiplyMatrices( m, this );

    },

    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;

    },

    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;

    },

    applyToBufferAttribute: function () {

        var v1 = new Vector3();

        return function applyToBufferAttribute( attribute ) {

            for ( var i = 0, l = attribute.count; i < l; i ++ ) {

                v1.x = attribute.getX( i );
                v1.y = attribute.getY( i );
                v1.z = attribute.getZ( i );

                v1.applyMatrix4( this );

                attribute.setXYZ( i, v1.x, v1.y, v1.z );

            }

            return attribute;

        };

    }(),

    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;

    },

    setPosition: function ( v ) {

        var te = this.elements;

        te[ 12 ] = v.x;
        te[ 13 ] = v.y;
        te[ 14 ] = v.z;

        return this;

    },

    getInverse: function ( m, throwOnDegenerate ) {

        // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
        var te = this.elements,
            me = m.elements,

            n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
            n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
            n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
            n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],

            t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
            t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
            t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
            t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;

        var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;

        if ( det === 0 ) {

            var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";

            if ( throwOnDegenerate === true ) {

                throw new Error( msg );

            } else {

                console.warn( msg );

            }

            return this.identity();

        }

        var detInv = 1 / det;

        te[ 0 ] = t11 * detInv;
        te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
        te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
        te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;

        te[ 4 ] = t12 * detInv;
        te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
        te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
        te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;

        te[ 8 ] = t13 * detInv;
        te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
        te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
        te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;

        te[ 12 ] = t14 * detInv;
        te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
        te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
        te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;

        return this;

    },

    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, 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;

    },

    makeShear: function ( x, y, z ) {

        this.set(

            1, y, z, 0,
            x, 1, z, 0,
            x, y, 1, 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 Vector3();
        var matrix = new Matrix4();

        return function decompose( 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.copy( this );

            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;

        };

    }(),

    makePerspective: function ( left, right, top, bottom, near, far ) {

        if ( far === undefined ) {

            console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );

        }

        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;

    },

    makeOrthographic: function ( left, right, top, bottom, near, far ) {

        var te = this.elements;
        var w = 1.0 / ( right - left );
        var h = 1.0 / ( top - bottom );
        var p = 1.0 / ( 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;

    },

    equals: function ( matrix ) {

        var te = this.elements;
        var me = matrix.elements;

        for ( var i = 0; i < 16; i ++ ) {

            if ( te[ i ] !== me[ i ] ) return false;

        }

        return true;

    },

    fromArray: function ( array, offset ) {

        if ( offset === undefined ) offset = 0;

        for ( var i = 0; i < 16; i ++ ) {

            this.elements[ i ] = array[ i + offset ];

        }

        return this;

    },

    toArray: function ( array, offset ) {

        if ( array === undefined ) array = [];
        if ( offset === undefined ) offset = 0;

        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;

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 */

function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {

    Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );

    this.image = { data: data, width: width, height: height };

    this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
    this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;

    this.generateMipmaps = false;
    this.flipY = false;
    this.unpackAlignment = 1;

}

DataTexture.prototype = Object.create( Texture.prototype );
DataTexture.prototype.constructor = DataTexture;

DataTexture.prototype.isDataTexture = true;

/**
 * @author mrdoob / http://mrdoob.com/
 */

function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {

    images = images !== undefined ? images : [];
    mapping = mapping !== undefined ? mapping : CubeReflectionMapping;

    Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );

    this.flipY = false;

}

CubeTexture.prototype = Object.create( Texture.prototype );
CubeTexture.prototype.constructor = CubeTexture;

CubeTexture.prototype.isCubeTexture = true;

Object.defineProperty( CubeTexture.prototype, 'images', {

    get: function () {

        return this.image;

    },

    set: function ( value ) {

        this.image = value;

    }

} );

/**
 * @author tschw
 *
 * Uniforms of a program.
 * Those form a tree structure with a special top-level container for the root,
 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
 *
 *
 * Properties of inner nodes including the top-level container:
 *
 * .seq - array of nested uniforms
 * .map - nested uniforms by name
 *
 *
 * Methods of all nodes except the top-level container:
 *
 * .setValue( gl, value, [renderer] )
 *
 *         uploads a uniform value(s)
 *      the 'renderer' parameter is needed for sampler uniforms
 *
 *
 * Static methods of the top-level container (renderer factorizations):
 *
 * .upload( gl, seq, values, renderer )
 *
 *         sets uniforms in 'seq' to 'values[id].value'
 *
 * .seqWithValue( seq, values ) : filteredSeq
 *
 *         filters 'seq' entries with corresponding entry in values
 *
 *
 * Methods of the top-level container (renderer factorizations):
 *
 * .setValue( gl, name, value )
 *
 *         sets uniform with  name 'name' to 'value'
 *
 * .set( gl, obj, prop )
 *
 *         sets uniform from object and property with same name than uniform
 *
 * .setOptional( gl, obj, prop )
 *
 *         like .set for an optional property of the object
 *
 */

var emptyTexture = new Texture();
var emptyCubeTexture = new CubeTexture();

// --- Base for inner nodes (including the root) ---

function UniformContainer() {

    this.seq = [];
    this.map = {};

}

// --- Utilities ---

// Array Caches (provide typed arrays for temporary by size)

var arrayCacheF32 = [];
var arrayCacheI32 = [];

// Float32Array caches used for uploading Matrix uniforms

var mat4array = new Float32Array( 16 );
var mat3array = new Float32Array( 9 );

// Flattening for arrays of vectors and matrices

function flatten( array, nBlocks, blockSize ) {

    var firstElem = array[ 0 ];

    if ( firstElem <= 0 || firstElem > 0 ) return array;
    // unoptimized: ! isNaN( firstElem )
    // see http://jacksondunstan.com/articles/983

    var n = nBlocks * blockSize,
        r = arrayCacheF32[ n ];

    if ( r === undefined ) {

        r = new Float32Array( n );
        arrayCacheF32[ n ] = r;

    }

    if ( nBlocks !== 0 ) {

        firstElem.toArray( r, 0 );

        for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {

            offset += blockSize;
            array[ i ].toArray( r, offset );

        }

    }

    return r;

}

// Texture unit allocation

function allocTexUnits( renderer, n ) {

    var r = arrayCacheI32[ n ];

    if ( r === undefined ) {

        r = new Int32Array( n );
        arrayCacheI32[ n ] = r;

    }

    for ( var i = 0; i !== n; ++ i )
        r[ i ] = renderer.allocTextureUnit();

    return r;

}

// --- Setters ---

// Note: Defining these methods externally, because they come in a bunch
// and this way their names minify.

// Single scalar

function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }
function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }

// Single float vector (from flat array or THREE.VectorN)

function setValue2fv( gl, v ) {

    if ( v.x === undefined ) gl.uniform2fv( this.addr, v );
    else gl.uniform2f( this.addr, v.x, v.y );

}

function setValue3fv( gl, v ) {

    if ( v.x !== undefined )
        gl.uniform3f( this.addr, v.x, v.y, v.z );
    else if ( v.r !== undefined )
        gl.uniform3f( this.addr, v.r, v.g, v.b );
    else
        gl.uniform3fv( this.addr, v );

}

function setValue4fv( gl, v ) {

    if ( v.x === undefined ) gl.uniform4fv( this.addr, v );
    else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );

}

// Single matrix (from flat array or MatrixN)

function setValue2fm( gl, v ) {

    gl.uniformMatrix2fv( this.addr, false, v.elements || v );

}

function setValue3fm( gl, v ) {

    if ( v.elements === undefined ) {

        gl.uniformMatrix3fv( this.addr, false, v );

    } else {

        mat3array.set( v.elements );
        gl.uniformMatrix3fv( this.addr, false, mat3array );

    }

}

function setValue4fm( gl, v ) {

    if ( v.elements === undefined ) {

        gl.uniformMatrix4fv( this.addr, false, v );

    } else {

        mat4array.set( v.elements );
        gl.uniformMatrix4fv( this.addr, false, mat4array );

    }

}

// Single texture (2D / Cube)

function setValueT1( gl, v, renderer ) {

    var unit = renderer.allocTextureUnit();
    gl.uniform1i( this.addr, unit );
    renderer.setTexture2D( v || emptyTexture, unit );

}

function setValueT6( gl, v, renderer ) {

    var unit = renderer.allocTextureUnit();
    gl.uniform1i( this.addr, unit );
    renderer.setTextureCube( v || emptyCubeTexture, unit );

}

// Integer / Boolean vectors or arrays thereof (always flat arrays)

function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }
function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }
function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }

// Helper to pick the right setter for the singular case

function getSingularSetter( type ) {

    switch ( type ) {

        case 0x1406: return setValue1f; // FLOAT
        case 0x8b50: return setValue2fv; // _VEC2
        case 0x8b51: return setValue3fv; // _VEC3
        case 0x8b52: return setValue4fv; // _VEC4

        case 0x8b5a: return setValue2fm; // _MAT2
        case 0x8b5b: return setValue3fm; // _MAT3
        case 0x8b5c: return setValue4fm; // _MAT4

        case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
        case 0x8b60: return setValueT6; // SAMPLER_CUBE

        case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
        case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
        case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
        case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4

    }

}

// Array of scalars

function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }
function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }

// Array of vectors (flat or from THREE classes)

function setValueV2a( gl, v ) {

    gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );

}

function setValueV3a( gl, v ) {

    gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );

}

function setValueV4a( gl, v ) {

    gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );

}

// Array of matrices (flat or from THREE clases)

function setValueM2a( gl, v ) {

    gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );

}

function setValueM3a( gl, v ) {

    gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );

}

function setValueM4a( gl, v ) {

    gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );

}

// Array of textures (2D / Cube)

function setValueT1a( gl, v, renderer ) {

    var n = v.length,
        units = allocTexUnits( renderer, n );

    gl.uniform1iv( this.addr, units );

    for ( var i = 0; i !== n; ++ i ) {

        renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );

    }

}

function setValueT6a( gl, v, renderer ) {

    var n = v.length,
        units = allocTexUnits( renderer, n );

    gl.uniform1iv( this.addr, units );

    for ( var i = 0; i !== n; ++ i ) {

        renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );

    }

}

// Helper to pick the right setter for a pure (bottom-level) array

function getPureArraySetter( type ) {

    switch ( type ) {

        case 0x1406: return setValue1fv; // FLOAT
        case 0x8b50: return setValueV2a; // _VEC2
        case 0x8b51: return setValueV3a; // _VEC3
        case 0x8b52: return setValueV4a; // _VEC4

        case 0x8b5a: return setValueM2a; // _MAT2
        case 0x8b5b: return setValueM3a; // _MAT3
        case 0x8b5c: return setValueM4a; // _MAT4

        case 0x8b5e: return setValueT1a; // SAMPLER_2D
        case 0x8b60: return setValueT6a; // SAMPLER_CUBE

        case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
        case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
        case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
        case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4

    }

}

// --- Uniform Classes ---

function SingleUniform( id, activeInfo, addr ) {

    this.id = id;
    this.addr = addr;
    this.setValue = getSingularSetter( activeInfo.type );

    // this.path = activeInfo.name; // DEBUG

}

function PureArrayUniform( id, activeInfo, addr ) {

    this.id = id;
    this.addr = addr;
    this.size = activeInfo.size;
    this.setValue = getPureArraySetter( activeInfo.type );

    // this.path = activeInfo.name; // DEBUG

}

function StructuredUniform( id ) {

    this.id = id;

    UniformContainer.call( this ); // mix-in

}

StructuredUniform.prototype.setValue = function ( gl, value ) {

    // Note: Don't need an extra 'renderer' parameter, since samplers
    // are not allowed in structured uniforms.

    var seq = this.seq;

    for ( var i = 0, n = seq.length; i !== n; ++ i ) {

        var u = seq[ i ];
        u.setValue( gl, value[ u.id ] );

    }

};

// --- Top-level ---

// Parser - builds up the property tree from the path strings

var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;

// extracts
//     - the identifier (member name or array index)
//  - followed by an optional right bracket (found when array index)
//  - followed by an optional left bracket or dot (type of subscript)
//
// Note: These portions can be read in a non-overlapping fashion and
// allow straightforward parsing of the hierarchy that WebGL encodes
// in the uniform names.

function addUniform( container, uniformObject ) {

    container.seq.push( uniformObject );
    container.map[ uniformObject.id ] = uniformObject;

}

function parseUniform( activeInfo, addr, container ) {

    var path = activeInfo.name,
        pathLength = path.length;

    // reset RegExp object, because of the early exit of a previous run
    RePathPart.lastIndex = 0;

    for ( ; ; ) {

        var match = RePathPart.exec( path ),
            matchEnd = RePathPart.lastIndex,

            id = match[ 1 ],
            idIsIndex = match[ 2 ] === ']',
            subscript = match[ 3 ];

        if ( idIsIndex ) id = id | 0; // convert to integer

        if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {

            // bare name or "pure" bottom-level array "[0]" suffix

            addUniform( container, subscript === undefined ?
                    new SingleUniform( id, activeInfo, addr ) :
                    new PureArrayUniform( id, activeInfo, addr ) );

            break;

        } else {

            // step into inner node / create it in case it doesn't exist

            var map = container.map, next = map[ id ];

            if ( next === undefined ) {

                next = new StructuredUniform( id );
                addUniform( container, next );

            }

            container = next;

        }

    }

}

// Root Container

function WebGLUniforms( gl, program, renderer ) {

    UniformContainer.call( this );

    this.renderer = renderer;

    var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );

    for ( var i = 0; i < n; ++ i ) {

        var info = gl.getActiveUniform( program, i ),
            path = info.name,
            addr = gl.getUniformLocation( program, path );

        parseUniform( info, addr, this );

    }

}

WebGLUniforms.prototype.setValue = function ( gl, name, value ) {

    var u = this.map[ name ];

    if ( u !== undefined ) u.setValue( gl, value, this.renderer );

};

WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {

    var v = object[ name ];

    if ( v !== undefined ) this.setValue( gl, name, v );

};


// Static interface

WebGLUniforms.upload = function ( gl, seq, values, renderer ) {

    for ( var i = 0, n = seq.length; i !== n; ++ i ) {

        var u = seq[ i ],
            v = values[ u.id ];

        if ( v.needsUpdate !== false ) {

            // note: always updating when .needsUpdate is undefined
            u.setValue( gl, v.value, renderer );

        }

    }

};

WebGLUniforms.seqWithValue = function ( seq, values ) {

    var r = [];

    for ( var i = 0, n = seq.length; i !== n; ++ i ) {

        var u = seq[ i ];
        if ( u.id in values ) r.push( u );

    }

    return r;

};

/**
 * @author mrdoob / http://mrdoob.com/
 */

var 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 };

function Color( r, g, b ) {

    if ( g === undefined && b === undefined ) {

        // r is THREE.Color, hex or string
        return this.set( r );

    }

    return this.setRGB( r, g, b );

}

Object.assign( Color.prototype, {

    isColor: true,

    r: 1, g: 1, b: 1,

    set: function ( value ) {

        if ( value && value.isColor ) {

            this.copy( value );

        } else if ( typeof value === 'number' ) {

            this.setHex( value );

        } else if ( typeof value === 'string' ) {

            this.setStyle( value );

        }

        return this;

    },

    setScalar: function ( scalar ) {

        this.r = scalar;
        this.g = scalar;
        this.b = scalar;

        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 () {

        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 ) * 6 * ( 2 / 3 - t );
            return p;

        }

        return function setHSL( h, s, l ) {

            // h,s,l ranges are in 0.0 - 1.0
            h = _Math.euclideanModulo( h, 1 );
            s = _Math.clamp( s, 0, 1 );
            l = _Math.clamp( l, 0, 1 );

            if ( s === 0 ) {

                this.r = this.g = this.b = l;

            } else {

                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 ) {

        function handleAlpha( string ) {

            if ( string === undefined ) return;

            if ( parseFloat( string ) < 1 ) {

                console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );

            }

        }


        var m;

        if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {

            // rgb / hsl

            var color;
            var name = m[ 1 ];
            var components = m[ 2 ];

            switch ( name ) {

                case 'rgb':
                case 'rgba':

                    if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

                        // rgb(255,0,0) rgba(255,0,0,0.5)
                        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;

                        handleAlpha( color[ 5 ] );

                        return this;

                    }

                    if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

                        // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
                        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;

                        handleAlpha( color[ 5 ] );

                        return this;

                    }

                    break;

                case 'hsl':
                case 'hsla':

                    if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

                        // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
                        var h = parseFloat( color[ 1 ] ) / 360;
                        var s = parseInt( color[ 2 ], 10 ) / 100;
                        var l = parseInt( color[ 3 ], 10 ) / 100;

                        handleAlpha( color[ 5 ] );

                        return this.setHSL( h, s, l );

                    }

                    break;

            }

        } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {

            // hex color

            var hex = m[ 1 ];
            var size = hex.length;

            if ( size === 3 ) {

                // #ff0
                this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
                this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
                this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;

                return this;

            } else if ( size === 6 ) {

                // #ff0000
                this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
                this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
                this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;

                return this;

            }

        }

        if ( style && style.length > 0 ) {

            // color keywords
            var hex = ColorKeywords[ style ];

            if ( hex !== undefined ) {

                // red
                this.setHex( hex );

            } else {

                // unknown color
                console.warn( 'THREE.Color: Unknown color ' + style );

            }

        }

        return this;

    },

    clone: function () {

        return new this.constructor( this.r, this.g, this.b );

    },

    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;

    },

    sub: function( color ) {

        this.r = Math.max( 0, this.r - color.r );
        this.g = Math.max( 0, this.g - color.g );
        this.b = Math.max( 0, this.b - color.b );

        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, offset ) {

        if ( offset === undefined ) offset = 0;

        this.r = array[ offset ];
        this.g = array[ offset + 1 ];
        this.b = array[ offset + 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;

    },

    toJSON: function () {

        return this.getHex();

    }

} );

/**
 * Uniforms library for shared webgl shaders
 */

var UniformsLib = {

    common: {

        diffuse: { value: new Color( 0xeeeeee ) },
        opacity: { value: 1.0 },

        map: { value: null },
        offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },

        specularMap: { value: null },
        alphaMap: { value: null },

        envMap: { value: null },
        flipEnvMap: { value: - 1 },
        reflectivity: { value: 1.0 },
        refractionRatio: { value: 0.98 }

    },

    aomap: {

        aoMap: { value: null },
        aoMapIntensity: { value: 1 }

    },

    lightmap: {

        lightMap: { value: null },
        lightMapIntensity: { value: 1 }

    },

    emissivemap: {

        emissiveMap: { value: null }

    },

    bumpmap: {

        bumpMap: { value: null },
        bumpScale: { value: 1 }

    },

    normalmap: {

        normalMap: { value: null },
        normalScale: { value: new Vector2( 1, 1 ) }

    },

    displacementmap: {

        displacementMap: { value: null },
        displacementScale: { value: 1 },
        displacementBias: { value: 0 }

    },

    roughnessmap: {

        roughnessMap: { value: null }

    },

    metalnessmap: {

        metalnessMap: { value: null }

    },

    gradientmap: {

        gradientMap: { value: null }

    },

    fog: {

        fogDensity: { value: 0.00025 },
        fogNear: { value: 1 },
        fogFar: { value: 2000 },
        fogColor: { value: new Color( 0xffffff ) }

    },

    lights: {

        ambientLightColor: { value: [] },

        directionalLights: { value: [], properties: {
            direction: {},
            color: {},

            shadow: {},
            shadowBias: {},
            shadowRadius: {},
            shadowMapSize: {}
        } },

        directionalShadowMap: { value: [] },
        directionalShadowMatrix: { value: [] },

        spotLights: { value: [], properties: {
            color: {},
            position: {},
            direction: {},
            distance: {},
            coneCos: {},
            penumbraCos: {},
            decay: {},

            shadow: {},
            shadowBias: {},
            shadowRadius: {},
            shadowMapSize: {}
        } },

        spotShadowMap: { value: [] },
        spotShadowMatrix: { value: [] },

        pointLights: { value: [], properties: {
            color: {},
            position: {},
            decay: {},
            distance: {},

            shadow: {},
            shadowBias: {},
            shadowRadius: {},
            shadowMapSize: {}
        } },

        pointShadowMap: { value: [] },
        pointShadowMatrix: { value: [] },

        hemisphereLights: { value: [], properties: {
            direction: {},
            skyColor: {},
            groundColor: {}
        } },

        // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
        rectAreaLights: { value: [], properties: {
            color: {},
            position: {},
            width: {},
            height: {}
        } }

    },

    points: {

        diffuse: { value: new Color( 0xeeeeee ) },
        opacity: { value: 1.0 },
        size: { value: 1.0 },
        scale: { value: 1.0 },
        map: { value: null },
        offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }

    }

};

/**
 * Uniform Utilities
 */

var 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 && ( parameter_src.isColor ||
                    parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
                    parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
                    parameter_src.isTexture ) ) {

                    uniforms_dst[ u ][ p ] = parameter_src.clone();

                } else if ( Array.isArray( parameter_src ) ) {

                    uniforms_dst[ u ][ p ] = parameter_src.slice();

                } else {

                    uniforms_dst[ u ][ p ] = parameter_src;

                }

            }

        }

        return uniforms_dst;

    }

};

var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";

var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";

var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";

var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";

var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";

var begin_vertex = "\nvec3 transformed = vec3( position );\n";

var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";

var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE  = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS  = 0.5 / LUT_SIZE;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";

var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";

var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";

var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";

var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";

var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";

var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";

var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";

var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";

var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";

var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n";

var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1  (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale =  bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";

var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n";

var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";

var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";

var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";

var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";

var encodings_fragment = "  gl_FragColor = linearToOutputTexel( gl_FragColor );\n";

var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M      = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM            = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D      = max( maxRange / maxRGB, 1.0 );\n\tD            = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value )  {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";

var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = asin( flipNormal * reflectVec.y ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";

var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";

var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";

var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";

var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";

var fog_pars_vertex = "#ifdef USE_FOG\n  varying float fogDepth;\n#endif\n";

var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";

var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n";

var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";

var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";

var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";

var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";

var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";

var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";

var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";

var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";

var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\n\t\tvec4 t = texture2D( ltcMat, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3(   1,   0, t.y ),\n\t\t\tvec3(   0, t.z,   0 ),\n\t\t\tvec3( t.w,   0, t.x )\n\t\t);\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";

var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";

var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif";

var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";

var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";

var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n";

var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";

var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";

var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";

var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n";

var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";

var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";

var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";

var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";

var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";

var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n";

var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";

var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";

var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";

var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";

var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n";

var dithering_fragment = "#if defined( DITHERING )\n  gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";

var dithering_pars_fragment = "#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n";

var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";

var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";

var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";

var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";

var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";

var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";

var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";

var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";

var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif\n";

var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";

var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";

var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";

var tonemapping_fragment = "#if defined( TONE_MAPPING )\n  gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";

var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";

var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";

var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n";

var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif";

var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";

var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";

var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";

var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n";

var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";

var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";

var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";

var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n";

var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include <common>\n#include <packing>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n";

var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include <common>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <skinbase_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition;\n}\n";

var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";

var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";

var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";

var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";

var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <normal_flip>\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";

var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n";

var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <normal_flip>\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";

var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";

var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";

var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";

var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";

var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";

var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";

var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";

var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";

var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";

var shadow_frag = "uniform float opacity;\n#include <common>\n#include <packing>\n#include <bsdfs>\n#include <lights_pars>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n";

var shadow_vert = "#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n}\n";

var ShaderChunk = {
    alphamap_fragment: alphamap_fragment,
    alphamap_pars_fragment: alphamap_pars_fragment,
    alphatest_fragment: alphatest_fragment,
    aomap_fragment: aomap_fragment,
    aomap_pars_fragment: aomap_pars_fragment,
    begin_vertex: begin_vertex,
    beginnormal_vertex: beginnormal_vertex,
    bsdfs: bsdfs,
    bumpmap_pars_fragment: bumpmap_pars_fragment,
    clipping_planes_fragment: clipping_planes_fragment,
    clipping_planes_pars_fragment: clipping_planes_pars_fragment,
    clipping_planes_pars_vertex: clipping_planes_pars_vertex,
    clipping_planes_vertex: clipping_planes_vertex,
    color_fragment: color_fragment,
    color_pars_fragment: color_pars_fragment,
    color_pars_vertex: color_pars_vertex,
    color_vertex: color_vertex,
    common: common,
    cube_uv_reflection_fragment: cube_uv_reflection_fragment,
    defaultnormal_vertex: defaultnormal_vertex,
    displacementmap_pars_vertex: displacementmap_pars_vertex,
    displacementmap_vertex: displacementmap_vertex,
    emissivemap_fragment: emissivemap_fragment,
    emissivemap_pars_fragment: emissivemap_pars_fragment,
    encodings_fragment: encodings_fragment,
    encodings_pars_fragment: encodings_pars_fragment,
    envmap_fragment: envmap_fragment,
    envmap_pars_fragment: envmap_pars_fragment,
    envmap_pars_vertex: envmap_pars_vertex,
    envmap_vertex: envmap_vertex,
    fog_vertex: fog_vertex,
    fog_pars_vertex: fog_pars_vertex,
    fog_fragment: fog_fragment,
    fog_pars_fragment: fog_pars_fragment,
    gradientmap_pars_fragment: gradientmap_pars_fragment,
    lightmap_fragment: lightmap_fragment,
    lightmap_pars_fragment: lightmap_pars_fragment,
    lights_lambert_vertex: lights_lambert_vertex,
    lights_pars: lights_pars,
    lights_phong_fragment: lights_phong_fragment,
    lights_phong_pars_fragment: lights_phong_pars_fragment,
    lights_physical_fragment: lights_physical_fragment,
    lights_physical_pars_fragment: lights_physical_pars_fragment,
    lights_template: lights_template,
    logdepthbuf_fragment: logdepthbuf_fragment,
    logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
    logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
    logdepthbuf_vertex: logdepthbuf_vertex,
    map_fragment: map_fragment,
    map_pars_fragment: map_pars_fragment,
    map_particle_fragment: map_particle_fragment,
    map_particle_pars_fragment: map_particle_pars_fragment,
    metalnessmap_fragment: metalnessmap_fragment,
    metalnessmap_pars_fragment: metalnessmap_pars_fragment,
    morphnormal_vertex: morphnormal_vertex,
    morphtarget_pars_vertex: morphtarget_pars_vertex,
    morphtarget_vertex: morphtarget_vertex,
    normal_flip: normal_flip,
    normal_fragment: normal_fragment,
    normalmap_pars_fragment: normalmap_pars_fragment,
    packing: packing,
    premultiplied_alpha_fragment: premultiplied_alpha_fragment,
    project_vertex: project_vertex,
    dithering_fragment: dithering_fragment,
    dithering_pars_fragment: dithering_pars_fragment,
    roughnessmap_fragment: roughnessmap_fragment,
    roughnessmap_pars_fragment: roughnessmap_pars_fragment,
    shadowmap_pars_fragment: shadowmap_pars_fragment,
    shadowmap_pars_vertex: shadowmap_pars_vertex,
    shadowmap_vertex: shadowmap_vertex,
    shadowmask_pars_fragment: shadowmask_pars_fragment,
    skinbase_vertex: skinbase_vertex,
    skinning_pars_vertex: skinning_pars_vertex,
    skinning_vertex: skinning_vertex,
    skinnormal_vertex: skinnormal_vertex,
    specularmap_fragment: specularmap_fragment,
    specularmap_pars_fragment: specularmap_pars_fragment,
    tonemapping_fragment: tonemapping_fragment,
    tonemapping_pars_fragment: tonemapping_pars_fragment,
    uv_pars_fragment: uv_pars_fragment,
    uv_pars_vertex: uv_pars_vertex,
    uv_vertex: uv_vertex,
    uv2_pars_fragment: uv2_pars_fragment,
    uv2_pars_vertex: uv2_pars_vertex,
    uv2_vertex: uv2_vertex,
    worldpos_vertex: worldpos_vertex,

    cube_frag: cube_frag,
    cube_vert: cube_vert,
    depth_frag: depth_frag,
    depth_vert: depth_vert,
    distanceRGBA_frag: distanceRGBA_frag,
    distanceRGBA_vert: distanceRGBA_vert,
    equirect_frag: equirect_frag,
    equirect_vert: equirect_vert,
    linedashed_frag: linedashed_frag,
    linedashed_vert: linedashed_vert,
    meshbasic_frag: meshbasic_frag,
    meshbasic_vert: meshbasic_vert,
    meshlambert_frag: meshlambert_frag,
    meshlambert_vert: meshlambert_vert,
    meshphong_frag: meshphong_frag,
    meshphong_vert: meshphong_vert,
    meshphysical_frag: meshphysical_frag,
    meshphysical_vert: meshphysical_vert,
    normal_frag: normal_frag,
    normal_vert: normal_vert,
    points_frag: points_frag,
    points_vert: points_vert,
    shadow_frag: shadow_frag,
    shadow_vert: shadow_vert
};

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 */

var ShaderLib = {

    basic: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.aomap,
            UniformsLib.lightmap,
            UniformsLib.fog
        ] ),

        vertexShader: ShaderChunk.meshbasic_vert,
        fragmentShader: ShaderChunk.meshbasic_frag

    },

    lambert: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.aomap,
            UniformsLib.lightmap,
            UniformsLib.emissivemap,
            UniformsLib.fog,
            UniformsLib.lights,
            {
                emissive: { value: new Color( 0x000000 ) }
            }
        ] ),

        vertexShader: ShaderChunk.meshlambert_vert,
        fragmentShader: ShaderChunk.meshlambert_frag

    },

    phong: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.aomap,
            UniformsLib.lightmap,
            UniformsLib.emissivemap,
            UniformsLib.bumpmap,
            UniformsLib.normalmap,
            UniformsLib.displacementmap,
            UniformsLib.gradientmap,
            UniformsLib.fog,
            UniformsLib.lights,
            {
                emissive: { value: new Color( 0x000000 ) },
                specular: { value: new Color( 0x111111 ) },
                shininess: { value: 30 }
            }
        ] ),

        vertexShader: ShaderChunk.meshphong_vert,
        fragmentShader: ShaderChunk.meshphong_frag

    },

    standard: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.aomap,
            UniformsLib.lightmap,
            UniformsLib.emissivemap,
            UniformsLib.bumpmap,
            UniformsLib.normalmap,
            UniformsLib.displacementmap,
            UniformsLib.roughnessmap,
            UniformsLib.metalnessmap,
            UniformsLib.fog,
            UniformsLib.lights,
            {
                emissive: { value: new Color( 0x000000 ) },
                roughness: { value: 0.5 },
                metalness: { value: 0.5 },
                envMapIntensity: { value: 1 } // temporary
            }
        ] ),

        vertexShader: ShaderChunk.meshphysical_vert,
        fragmentShader: ShaderChunk.meshphysical_frag

    },

    points: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.points,
            UniformsLib.fog
        ] ),

        vertexShader: ShaderChunk.points_vert,
        fragmentShader: ShaderChunk.points_frag

    },

    dashed: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.fog,
            {
                scale: { value: 1 },
                dashSize: { value: 1 },
                totalSize: { value: 2 }
            }
        ] ),

        vertexShader: ShaderChunk.linedashed_vert,
        fragmentShader: ShaderChunk.linedashed_frag

    },

    depth: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.displacementmap
        ] ),

        vertexShader: ShaderChunk.depth_vert,
        fragmentShader: ShaderChunk.depth_frag

    },

    normal: {

        uniforms: UniformsUtils.merge( [
            UniformsLib.common,
            UniformsLib.bumpmap,
            UniformsLib.normalmap,
            UniformsLib.displacementmap,
            {
                opacity: { value: 1.0 }
            }
        ] ),

        vertexShader: ShaderChunk.normal_vert,
        fragmentShader: ShaderChunk.normal_frag

    },

    /* -------------------------------------------------------------------------
    //    Cube map shader
     ------------------------------------------------------------------------- */

    cube: {

        uniforms: {
            tCube: { value: null },
            tFlip: { value: - 1 },
            opacity: { value: 1.0 }
        },

        vertexShader: ShaderChunk.cube_vert,
        fragmentShader: ShaderChunk.cube_frag

    },

    /* -------------------------------------------------------------------------
    //    Cube map shader
     ------------------------------------------------------------------------- */

    equirect: {

        uniforms: {
            tEquirect: { value: null },
            tFlip: { value: - 1 }
        },

        vertexShader: ShaderChunk.equirect_vert,
        fragmentShader: ShaderChunk.equirect_frag

    },

    distanceRGBA: {

        uniforms: {
            lightPos: { value: new Vector3() }
        },

        vertexShader: ShaderChunk.distanceRGBA_vert,
        fragmentShader: ShaderChunk.distanceRGBA_frag

    }

};

ShaderLib.physical = {

    uniforms: UniformsUtils.merge( [
        ShaderLib.standard.uniforms,
        {
            clearCoat: { value: 0 },
            clearCoatRoughness: { value: 0 }
        }
    ] ),

    vertexShader: ShaderChunk.meshphysical_vert,
    fragmentShader: ShaderChunk.meshphysical_frag

};

/**
 * @author bhouston / http://clara.io
 */

function Box2( min, max ) {

    this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
    this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );

}

Object.assign( Box2.prototype, {

    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 Vector2();

        return function setFromCenterAndSize( center, size ) {

            var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
            this.min.copy( center ).sub( halfSize );
            this.max.copy( center ).add( halfSize );

            return this;

        };

    }(),

    clone: function () {

        return new this.constructor().copy( 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;

    },

    isEmpty: 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 );

    },

    getCenter: function ( optionalTarget ) {

        var result = optionalTarget || new Vector2();
        return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

    },

    getSize: function ( optionalTarget ) {

        var result = optionalTarget || new Vector2();
        return this.isEmpty() ? result.set( 0, 0 ) : 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 ) {

        return point.x < this.min.x || point.x > this.max.x ||
            point.y < this.min.y || point.y > this.max.y ? false : true;

    },

    containsBox: function ( box ) {

        return this.min.x <= box.min.x && box.max.x <= this.max.x &&
            this.min.y <= box.min.y && box.max.y <= this.max.y;

    },

    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 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 )
        );

    },

    intersectsBox: function ( box ) {

        // using 4 splitting planes to rule out intersections

        return box.max.x < this.min.x || box.min.x > this.max.x ||
            box.max.y < this.min.y || box.min.y > this.max.y ? false : true;

    },

    clampPoint: function ( point, optionalTarget ) {

        var result = optionalTarget || new Vector2();
        return result.copy( point ).clamp( this.min, this.max );

    },

    distanceToPoint: function () {

        var v1 = new Vector2();

        return function distanceToPoint( 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 );

    }

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function LensFlarePlugin( renderer, flares ) {

    var gl = renderer.context;
    var state = renderer.state;

    var vertexBuffer, elementBuffer;
    var shader, program, attributes, uniforms;

    var tempTexture, occlusionTexture;

    function init() {

        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();

        state.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 );

        state.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 );

        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" )

        };

        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, viewport ) {

        if ( flares.length === 0 ) return;

        var tempPosition = new Vector3();

        var invAspect = viewport.w / viewport.z,
            halfViewportWidth = viewport.z * 0.5,
            halfViewportHeight = viewport.w * 0.5;

        var size = 16 / viewport.w,
            scale = new Vector2( size * invAspect, size );

        var screenPosition = new Vector3( 1, 1, 0 ),
            screenPositionPixels = new Vector2( 1, 1 );

        var validArea = new Box2();

        validArea.min.set( viewport.x, viewport.y );
        validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );

        if ( program === undefined ) {

            init();

        }

        gl.useProgram( program );

        state.initAttributes();
        state.enableAttribute( attributes.vertex );
        state.enableAttribute( attributes.uv );
        state.disableUnusedAttributes();

        // loop through all lens flares to update their occlusion and positions
        // setup gl and common used attribs/uniforms

        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 );

        state.disable( gl.CULL_FACE );
        state.buffers.depth.setMask( false );

        for ( var i = 0, l = flares.length; i < l; i ++ ) {

            size = 16 / viewport.w;
            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.applyMatrix4( camera.projectionMatrix );

            // setup arrays for gl programs

            screenPosition.copy( tempPosition );

            // horizontal and vertical coordinate of the lower left corner of the pixels to copy

            screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;
            screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;

            // screen cull

            if ( validArea.containsPoint( screenPositionPixels ) === true ) {

                // save current RGB to temp texture

                state.activeTexture( gl.TEXTURE0 );
                state.bindTexture( gl.TEXTURE_2D, null );
                state.activeTexture( gl.TEXTURE1 );
                state.bindTexture( gl.TEXTURE_2D, tempTexture );
                gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 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 );

                state.disable( gl.BLEND );
                state.enable( gl.DEPTH_TEST );

                gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );


                // copy result to occlusionMap

                state.activeTexture( gl.TEXTURE0 );
                state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
                gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );


                // restore graphics

                gl.uniform1i( uniforms.renderType, 1 );
                state.disable( gl.DEPTH_TEST );

                state.activeTexture( gl.TEXTURE1 );
                state.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 );
                state.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 / viewport.w;

                        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 );

                        state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
                        renderer.setTexture2D( sprite.texture, 1 );

                        gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );

                    }

                }

            }

        }

        // restore gl

        state.enable( gl.CULL_FACE );
        state.enable( gl.DEPTH_TEST );
        state.buffers.depth.setMask( 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;

    }

}

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function SpritePlugin( renderer, sprites ) {

    var gl = renderer.context;
    var state = renderer.state;

    var vertexBuffer, elementBuffer;
    var program, attributes, uniforms;

    var texture;

    // decompose matrixWorld

    var spritePosition = new Vector3();
    var spriteRotation = new Quaternion();
    var spriteScale = new Vector3();

    function init() {

        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.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
        canvas.width = 8;
        canvas.height = 8;

        var context = canvas.getContext( '2d' );
        context.fillStyle = 'white';
        context.fillRect( 0, 0, 8, 8 );

        texture = new Texture( canvas );
        texture.needsUpdate = true;

    }

    this.render = function ( scene, camera ) {

        if ( sprites.length === 0 ) return;

        // setup gl

        if ( program === undefined ) {

            init();

        }

        gl.useProgram( program );

        state.initAttributes();
        state.enableAttribute( attributes.position );
        state.enableAttribute( attributes.uv );
        state.disableUnusedAttributes();

        state.disable( gl.CULL_FACE );
        state.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 );

        state.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.isFog ) {

                gl.uniform1f( uniforms.fogNear, fog.near );
                gl.uniform1f( uniforms.fogFar, fog.far );

                gl.uniform1i( uniforms.fogType, 1 );
                oldFogType = 1;
                sceneFogType = 1;

            } else if ( fog.isFogExp2 ) {

                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;

            if ( material.visible === false ) continue;

            sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );

            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 );

            state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
            state.buffers.depth.setTest( material.depthTest );
            state.buffers.depth.setMask( material.depthWrite );

            if ( material.map ) {

                renderer.setTexture2D( material.map, 0 );

            } else {

                renderer.setTexture2D( texture, 0 );

            }

            gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );

            sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );

        }

        // restore gl

        state.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;',

            '#define SHADER_NAME ' + 'SpriteMaterial',

            '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;',

            '#define SHADER_NAME ' + 'SpriteMaterial',

            '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;',
                        '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.renderOrder !== b.renderOrder ) {

            return a.renderOrder - b.renderOrder;

        } else if ( a.z !== b.z ) {

            return b.z - a.z;

        } else {

            return b.id - a.id;

        }

    }

}

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

var materialId = 0;

function Material() {

    Object.defineProperty( this, 'id', { value: materialId ++ } );

    this.uuid = _Math.generateUUID();

    this.name = '';
    this.type = 'Material';

    this.fog = true;
    this.lights = true;

    this.blending = NormalBlending;
    this.side = FrontSide;
    this.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading
    this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors

    this.opacity = 1;
    this.transparent = false;

    this.blendSrc = SrcAlphaFactor;
    this.blendDst = OneMinusSrcAlphaFactor;
    this.blendEquation = AddEquation;
    this.blendSrcAlpha = null;
    this.blendDstAlpha = null;
    this.blendEquationAlpha = null;

    this.depthFunc = LessEqualDepth;
    this.depthTest = true;
    this.depthWrite = true;

    this.clippingPlanes = null;
    this.clipIntersection = false;
    this.clipShadows = false;

    this.colorWrite = true;

    this.precision = null; // override the renderer's default precision for this material

    this.polygonOffset = false;
    this.polygonOffsetFactor = 0;
    this.polygonOffsetUnits = 0;

    this.dithering = false;

    this.alphaTest = 0;
    this.premultipliedAlpha = false;

    this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer

    this.visible = true;

    this.needsUpdate = true;

}

Object.assign( Material.prototype, EventDispatcher.prototype, {

    isMaterial: true,

    onBeforeCompile: function () {},

    setValues: function ( values ) {

        if ( values === undefined ) return;

        for ( var key in values ) {

            var newValue = values[ key ];

            if ( newValue === undefined ) {

                console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
                continue;

            }

            var currentValue = this[ key ];

            if ( currentValue === undefined ) {

                console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
                continue;

            }

            if ( currentValue && currentValue.isColor ) {

                currentValue.set( newValue );

            } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {

                currentValue.copy( newValue );

            } else if ( key === 'overdraw' ) {

                // ensure overdraw is backwards-compatible with legacy boolean type
                this[ key ] = Number( newValue );

            } else {

                this[ key ] = newValue;

            }

        }

    },

    toJSON: function ( meta ) {

        var isRoot = meta === undefined;

        if ( isRoot ) {

            meta = {
                textures: {},
                images: {}
            };

        }

        var data = {
            metadata: {
                version: 4.5,
                type: 'Material',
                generator: 'Material.toJSON'
            }
        };

        // standard Material serialization
        data.uuid = this.uuid;
        data.type = this.type;

        if ( this.name !== '' ) data.name = this.name;

        if ( this.color && this.color.isColor ) data.color = this.color.getHex();

        if ( this.roughness !== undefined ) data.roughness = this.roughness;
        if ( this.metalness !== undefined ) data.metalness = this.metalness;

        if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
        if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
        if ( this.shininess !== undefined ) data.shininess = this.shininess;
        if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
        if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;

        if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
        if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
        if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
        if ( this.bumpMap && this.bumpMap.isTexture ) {

            data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
            data.bumpScale = this.bumpScale;

        }
        if ( this.normalMap && this.normalMap.isTexture ) {

            data.normalMap = this.normalMap.toJSON( meta ).uuid;
            data.normalScale = this.normalScale.toArray();

        }
        if ( this.displacementMap && this.displacementMap.isTexture ) {

            data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
            data.displacementScale = this.displacementScale;
            data.displacementBias = this.displacementBias;

        }
        if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
        if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;

        if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
        if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;

        if ( this.envMap && this.envMap.isTexture ) {

            data.envMap = this.envMap.toJSON( meta ).uuid;
            data.reflectivity = this.reflectivity; // Scale behind envMap

        }

        if ( this.gradientMap && this.gradientMap.isTexture ) {

            data.gradientMap = this.gradientMap.toJSON( meta ).uuid;

        }

        if ( this.size !== undefined ) data.size = this.size;
        if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;

        if ( this.blending !== NormalBlending ) data.blending = this.blending;
        if ( this.shading !== SmoothShading ) data.shading = this.shading;
        if ( this.side !== FrontSide ) data.side = this.side;
        if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;

        if ( this.opacity < 1 ) data.opacity = this.opacity;
        if ( this.transparent === true ) data.transparent = this.transparent;

        data.depthFunc = this.depthFunc;
        data.depthTest = this.depthTest;
        data.depthWrite = this.depthWrite;

        if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
        if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
        if ( this.wireframe === true ) data.wireframe = this.wireframe;
        if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
        if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
        if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;

        data.skinning = this.skinning;
        data.morphTargets = this.morphTargets;

        data.dithering = this.dithering;

        // TODO: Copied from Object3D.toJSON

        function extractFromCache( cache ) {

            var values = [];

            for ( var key in cache ) {

                var data = cache[ key ];
                delete data.metadata;
                values.push( data );

            }

            return values;

        }

        if ( isRoot ) {

            var textures = extractFromCache( meta.textures );
            var images = extractFromCache( meta.images );

            if ( textures.length > 0 ) data.textures = textures;
            if ( images.length > 0 ) data.images = images;

        }

        return data;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( source ) {

        this.name = source.name;

        this.fog = source.fog;
        this.lights = source.lights;

        this.blending = source.blending;
        this.side = source.side;
        this.shading = source.shading;
        this.vertexColors = source.vertexColors;

        this.opacity = source.opacity;
        this.transparent = source.transparent;

        this.blendSrc = source.blendSrc;
        this.blendDst = source.blendDst;
        this.blendEquation = source.blendEquation;
        this.blendSrcAlpha = source.blendSrcAlpha;
        this.blendDstAlpha = source.blendDstAlpha;
        this.blendEquationAlpha = source.blendEquationAlpha;

        this.depthFunc = source.depthFunc;
        this.depthTest = source.depthTest;
        this.depthWrite = source.depthWrite;

        this.colorWrite = source.colorWrite;

        this.precision = source.precision;

        this.polygonOffset = source.polygonOffset;
        this.polygonOffsetFactor = source.polygonOffsetFactor;
        this.polygonOffsetUnits = source.polygonOffsetUnits;

        this.dithering = source.dithering;

        this.alphaTest = source.alphaTest;

        this.premultipliedAlpha = source.premultipliedAlpha;

        this.overdraw = source.overdraw;

        this.visible = source.visible;
        this.clipShadows = source.clipShadows;
        this.clipIntersection = source.clipIntersection;

        var srcPlanes = source.clippingPlanes,
            dstPlanes = null;

        if ( srcPlanes !== null ) {

            var n = srcPlanes.length;
            dstPlanes = new Array( n );

            for ( var i = 0; i !== n; ++ i )
                dstPlanes[ i ] = srcPlanes[ i ].clone();

        }

        this.clippingPlanes = dstPlanes;

        return this;

    },

    dispose: function () {

        this.dispatchEvent( { type: 'dispose' } );

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  defines: { "label" : "value" },
 *  uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
 *
 *  fragmentShader: <string>,
 *  vertexShader: <string>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  lights: <bool>,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>
 * }
 */

function ShaderMaterial( parameters ) {

    Material.call( this );

    this.type = 'ShaderMaterial';

    this.defines = {};
    this.uniforms = {};

    this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
    this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';

    this.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.clipping = false; // set to use user-defined clipping planes

    this.skinning = false; // set to use skinning attribute streams
    this.morphTargets = false; // set to use morph targets
    this.morphNormals = false; // set to use morph normals

    this.extensions = {
        derivatives: false, // set to use derivatives
        fragDepth: false, // set to use fragment depth values
        drawBuffers: false, // set to use draw buffers
        shaderTextureLOD: false // set to use shader texture LOD
    };

    // 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;

    if ( parameters !== undefined ) {

        if ( parameters.attributes !== undefined ) {

            console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );

        }

        this.setValues( parameters );

    }

}

ShaderMaterial.prototype = Object.create( Material.prototype );
ShaderMaterial.prototype.constructor = ShaderMaterial;

ShaderMaterial.prototype.isShaderMaterial = true;

ShaderMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.fragmentShader = source.fragmentShader;
    this.vertexShader = source.vertexShader;

    this.uniforms = UniformsUtils.clone( source.uniforms );

    this.defines = source.defines;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;

    this.lights = source.lights;
    this.clipping = source.clipping;

    this.skinning = source.skinning;

    this.morphTargets = source.morphTargets;
    this.morphNormals = source.morphNormals;

    this.extensions = source.extensions;

    return this;

};

ShaderMaterial.prototype.toJSON = function ( meta ) {

    var data = Material.prototype.toJSON.call( this, meta );

    data.uniforms = this.uniforms;
    data.vertexShader = this.vertexShader;
    data.fragmentShader = this.fragmentShader;

    return data;

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author bhouston / https://clara.io
 * @author WestLangley / http://github.com/WestLangley
 *
 * parameters = {
 *
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  alphaMap: new THREE.Texture( <Image> ),
 *
 *  displacementMap: new THREE.Texture( <Image> ),
 *  displacementScale: <float>,
 *  displacementBias: <float>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>
 * }
 */

function MeshDepthMaterial( parameters ) {

    Material.call( this );

    this.type = 'MeshDepthMaterial';

    this.depthPacking = BasicDepthPacking;

    this.skinning = false;
    this.morphTargets = false;

    this.map = null;

    this.alphaMap = null;

    this.displacementMap = null;
    this.displacementScale = 1;
    this.displacementBias = 0;

    this.wireframe = false;
    this.wireframeLinewidth = 1;

    this.fog = false;
    this.lights = false;

    this.setValues( parameters );

}

MeshDepthMaterial.prototype = Object.create( Material.prototype );
MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;

MeshDepthMaterial.prototype.isMeshDepthMaterial = true;

MeshDepthMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.depthPacking = source.depthPacking;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;

    this.map = source.map;

    this.alphaMap = source.alphaMap;

    this.displacementMap = source.displacementMap;
    this.displacementScale = source.displacementScale;
    this.displacementBias = source.displacementBias;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;

    return this;

};

/**
 * @author bhouston / http://clara.io
 * @author WestLangley / http://github.com/WestLangley
 */

function Box3( min, max ) {

    this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
    this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );

}

Object.assign( Box3.prototype, {

    isBox3: true,

    set: function ( min, max ) {

        this.min.copy( min );
        this.max.copy( max );

        return this;

    },

    setFromArray: function ( array ) {

        var minX = + Infinity;
        var minY = + Infinity;
        var minZ = + Infinity;

        var maxX = - Infinity;
        var maxY = - Infinity;
        var maxZ = - Infinity;

        for ( var i = 0, l = array.length; i < l; i += 3 ) {

            var x = array[ i ];
            var y = array[ i + 1 ];
            var z = array[ i + 2 ];

            if ( x < minX ) minX = x;
            if ( y < minY ) minY = y;
            if ( z < minZ ) minZ = z;

            if ( x > maxX ) maxX = x;
            if ( y > maxY ) maxY = y;
            if ( z > maxZ ) maxZ = z;

        }

        this.min.set( minX, minY, minZ );
        this.max.set( maxX, maxY, maxZ );

        return this;

    },

    setFromBufferAttribute: function ( attribute ) {

        var minX = + Infinity;
        var minY = + Infinity;
        var minZ = + Infinity;

        var maxX = - Infinity;
        var maxY = - Infinity;
        var maxZ = - Infinity;

        for ( var i = 0, l = attribute.count; i < l; i ++ ) {

            var x = attribute.getX( i );
            var y = attribute.getY( i );
            var z = attribute.getZ( i );

            if ( x < minX ) minX = x;
            if ( y < minY ) minY = y;
            if ( z < minZ ) minZ = z;

            if ( x > maxX ) maxX = x;
            if ( y > maxY ) maxY = y;
            if ( z > maxZ ) maxZ = z;

        }

        this.min.set( minX, minY, minZ );
        this.max.set( maxX, maxY, maxZ );

        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 Vector3();

        return function setFromCenterAndSize( 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 ( object ) {

        this.makeEmpty();

        return this.expandByObject( object );

    },

    clone: function () {

        return new this.constructor().copy( 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;

    },

    isEmpty: 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 );

    },

    getCenter: function ( optionalTarget ) {

        var result = optionalTarget || new Vector3();
        return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

    },

    getSize: function ( optionalTarget ) {

        var result = optionalTarget || new Vector3();
        return this.isEmpty() ? result.set( 0, 0, 0 ) : 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;

    },

    expandByObject: function () {

        // Computes the world-axis-aligned bounding box of an object (including its children),
        // accounting for both the object's, and children's, world transforms

        var v1 = new Vector3();

        return function expandByObject( object ) {

            var scope = this;

            object.updateMatrixWorld( true );

            object.traverse( function ( node ) {

                var i, l;

                var geometry = node.geometry;

                if ( geometry !== undefined ) {

                    if ( geometry.isGeometry ) {

                        var vertices = geometry.vertices;

                        for ( i = 0, l = vertices.length; i < l; i ++ ) {

                            v1.copy( vertices[ i ] );
                            v1.applyMatrix4( node.matrixWorld );

                            scope.expandByPoint( v1 );

                        }

                    } else if ( geometry.isBufferGeometry ) {

                        var attribute = geometry.attributes.position;

                        if ( attribute !== undefined ) {

                            for ( i = 0, l = attribute.count; i < l; i ++ ) {

                                v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );

                                scope.expandByPoint( v1 );

                            }

                        }

                    }

                }

            } );

            return this;

        };

    }(),

    containsPoint: function ( point ) {

        return 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 ? false : true;

    },

    containsBox: function ( box ) {

        return 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;

    },

    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 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 )
        );

    },

    intersectsBox: function ( box ) {

        // using 6 splitting planes to rule out intersections.
        return 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 ? false : true;

    },

    intersectsSphere: ( function () {

        var closestPoint = new Vector3();

        return function intersectsSphere( sphere ) {

            // Find the point on the AABB closest to the sphere center.
            this.clampPoint( sphere.center, closestPoint );

            // If that point is inside the sphere, the AABB and sphere intersect.
            return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

        };

    } )(),

    intersectsPlane: function ( plane ) {

        // We compute the minimum and maximum dot product values. If those values
        // are on the same side (back or front) of the plane, then there is no intersection.

        var min, max;

        if ( plane.normal.x > 0 ) {

            min = plane.normal.x * this.min.x;
            max = plane.normal.x * this.max.x;

        } else {

            min = plane.normal.x * this.max.x;
            max = plane.normal.x * this.min.x;

        }

        if ( plane.normal.y > 0 ) {

            min += plane.normal.y * this.min.y;
            max += plane.normal.y * this.max.y;

        } else {

            min += plane.normal.y * this.max.y;
            max += plane.normal.y * this.min.y;

        }

        if ( plane.normal.z > 0 ) {

            min += plane.normal.z * this.min.z;
            max += plane.normal.z * this.max.z;

        } else {

            min += plane.normal.z * this.max.z;
            max += plane.normal.z * this.min.z;

        }

        return ( min <= plane.constant && max >= plane.constant );

    },

    clampPoint: function ( point, optionalTarget ) {

        var result = optionalTarget || new Vector3();
        return result.copy( point ).clamp( this.min, this.max );

    },

    distanceToPoint: function () {

        var v1 = new Vector3();

        return function distanceToPoint( point ) {

            var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
            return clampedPoint.sub( point ).length();

        };

    }(),

    getBoundingSphere: function () {

        var v1 = new Vector3();

        return function getBoundingSphere( optionalTarget ) {

            var result = optionalTarget || new Sphere();

            this.getCenter( result.center );

            result.radius = this.getSize( v1 ).length() * 0.5;

            return result;

        };

    }(),

    intersect: function ( box ) {

        this.min.max( box.min );
        this.max.min( box.max );

        // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
        if( this.isEmpty() ) this.makeEmpty();

        return this;

    },

    union: function ( box ) {

        this.min.min( box.min );
        this.max.max( box.max );

        return this;

    },

    applyMatrix4: function () {

        var points = [
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3(),
            new Vector3()
        ];

        return function applyMatrix4( matrix ) {

            // transform of empty box is an empty box.
            if( this.isEmpty() ) return this;

            // 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.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 );

    }

} );

/**
 * @author bhouston / http://clara.io
 * @author mrdoob / http://mrdoob.com/
 */

function Sphere( center, radius ) {

    this.center = ( center !== undefined ) ? center : new Vector3();
    this.radius = ( radius !== undefined ) ? radius : 0;

}

Object.assign( Sphere.prototype, {

    set: function ( center, radius ) {

        this.center.copy( center );
        this.radius = radius;

        return this;

    },

    setFromPoints: function () {

        var box = new Box3();

        return function setFromPoints( points, optionalCenter ) {

            var center = this.center;

            if ( optionalCenter !== undefined ) {

                center.copy( optionalCenter );

            } else {

                box.setFromPoints( points ).getCenter( 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;

        };

    }(),

    clone: function () {

        return new this.constructor().copy( 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 );

    },

    intersectsBox: function ( box ) {

        return box.intersectsSphere( this );

    },

    intersectsPlane: function ( plane ) {

        // We use the following equation to compute the signed distance from
        // the center of the sphere to the plane.
        //
        // distance = q * n - d
        //
        // If this distance is greater than the radius of the sphere,
        // then there is no intersection.

        return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius;

    },

    clampPoint: function ( point, optionalTarget ) {

        var deltaLengthSq = this.center.distanceToSquared( point );

        var result = optionalTarget || new 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 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 );

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://clara.io
 * @author tschw
 */

function Matrix3() {

    this.elements = [

        1, 0, 0,
        0, 1, 0,
        0, 0, 1

    ];

    if ( arguments.length > 0 ) {

        console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );

    }

}

Object.assign( Matrix3.prototype, {

    isMatrix3: true,

    set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {

        var te = this.elements;

        te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
        te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
        te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;

        return this;

    },

    identity: function () {

        this.set(

            1, 0, 0,
            0, 1, 0,
            0, 0, 1

        );

        return this;

    },

    clone: function () {

        return new this.constructor().fromArray( this.elements );

    },

    copy: function ( m ) {

        var te = this.elements;
        var me = m.elements;

        te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
        te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
        te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];

        return this;

    },

    setFromMatrix4: function ( m ) {

        var me = m.elements;

        this.set(

            me[ 0 ], me[ 4 ], me[  8 ],
            me[ 1 ], me[ 5 ], me[  9 ],
            me[ 2 ], me[ 6 ], me[ 10 ]

        );

        return this;

    },

    applyToBufferAttribute: function () {

        var v1 = new Vector3();

        return function applyToBufferAttribute( attribute ) {

            for ( var i = 0, l = attribute.count; i < l; i ++ ) {

                v1.x = attribute.getX( i );
                v1.y = attribute.getY( i );
                v1.z = attribute.getZ( i );

                v1.applyMatrix3( this );

                attribute.setXYZ( i, v1.x, v1.y, v1.z );

            }

            return attribute;

        };

    }(),

    multiply: function ( m ) {

        return this.multiplyMatrices( this, m );

    },

    premultiply: function ( m ) {

        return this.multiplyMatrices( m, this );

    },

    multiplyMatrices: function ( a, b ) {

        var ae = a.elements;
        var be = b.elements;
        var te = this.elements;

        var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
        var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
        var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];

        var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
        var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
        var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];

        te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
        te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
        te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;

        te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
        te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
        te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;

        te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
        te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
        te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;

        return this;

    },

    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, throwOnDegenerate ) {

        if ( matrix && matrix.isMatrix4 ) {

            console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." );

        }

        var me = matrix.elements,
            te = this.elements,

            n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
            n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
            n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],

            t11 = n33 * n22 - n32 * n23,
            t12 = n32 * n13 - n33 * n12,
            t13 = n23 * n12 - n22 * n13,

            det = n11 * t11 + n21 * t12 + n31 * t13;

        if ( det === 0 ) {

            var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0";

            if ( throwOnDegenerate === true ) {

                throw new Error( msg );

            } else {

                console.warn( msg );

            }

            return this.identity();

        }

        var detInv = 1 / det;

        te[ 0 ] = t11 * detInv;
        te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
        te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;

        te[ 3 ] = t12 * detInv;
        te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
        te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;

        te[ 6 ] = t13 * detInv;
        te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
        te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;

        return this;

    },

    transpose: function () {

        var tmp, m = this.elements;

        tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
        tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
        tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;

        return this;

    },

    getNormalMatrix: function ( matrix4 ) {

        return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();

    },

    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;

    },

    equals: function ( matrix ) {

        var te = this.elements;
        var me = matrix.elements;

        for ( var i = 0; i < 9; i ++ ) {

            if ( te[ i ] !== me[ i ] ) return false;

        }

        return true;

    },

    fromArray: function ( array, offset ) {

        if ( offset === undefined ) offset = 0;

        for ( var i = 0; i < 9; i ++ ) {

            this.elements[ i ] = array[ i + offset ];

        }

        return this;

    },

    toArray: function ( array, offset ) {

        if ( array === undefined ) array = [];
        if ( offset === undefined ) offset = 0;

        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;

    }

} );

/**
 * @author bhouston / http://clara.io
 */

function Plane( normal, constant ) {

    this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
    this.constant = ( constant !== undefined ) ? constant : 0;

}

Object.assign( Plane.prototype, {

    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 Vector3();
        var v2 = new Vector3();

        return function setFromCoplanarPoints( 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;

        };

    }(),

    clone: function () {

        return new this.constructor().copy( 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 Vector3();
        return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );

    },

    intersectLine: function () {

        var v1 = new Vector3();

        return function intersectLine( line, optionalTarget ) {

            var result = optionalTarget || new 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 );

        };

    }(),

    intersectsLine: 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 );

    },

    intersectsBox: function ( box ) {

        return box.intersectsPlane( this );

    },

    intersectsSphere: function ( sphere ) {

        return sphere.intersectsPlane( this );

    },

    coplanarPoint: function ( optionalTarget ) {

        var result = optionalTarget || new Vector3();
        return result.copy( this.normal ).multiplyScalar( - this.constant );

    },

    applyMatrix4: function () {

        var v1 = new Vector3();
        var m1 = new Matrix3();

        return function applyMatrix4( matrix, optionalNormalMatrix ) {

            var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );

            // transform normal based on theory here:
            // http://www.songho.ca/opengl/gl_normaltransform.html
            var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
            var normal = this.normal.applyMatrix3( normalMatrix ).normalize();

            // recalculate constant (like in setFromNormalAndCoplanarPoint)
            this.constant = - referencePoint.dot( normal );

            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 );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author bhouston / http://clara.io
 */

function Frustum( p0, p1, p2, p3, p4, p5 ) {

    this.planes = [

        ( p0 !== undefined ) ? p0 : new Plane(),
        ( p1 !== undefined ) ? p1 : new Plane(),
        ( p2 !== undefined ) ? p2 : new Plane(),
        ( p3 !== undefined ) ? p3 : new Plane(),
        ( p4 !== undefined ) ? p4 : new Plane(),
        ( p5 !== undefined ) ? p5 : new Plane()

    ];

}

Object.assign( Frustum.prototype, {

    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;

    },

    clone: function () {

        return new this.constructor().copy( 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 Sphere();

        return function intersectsObject( object ) {

            var geometry = object.geometry;

            if ( geometry.boundingSphere === null )
                geometry.computeBoundingSphere();

            sphere.copy( geometry.boundingSphere )
                .applyMatrix4( object.matrixWorld );

            return this.intersectsSphere( sphere );

        };

    }(),

    intersectsSprite: function () {

        var sphere = new Sphere();

        return function intersectsSprite( sprite ) {

            sphere.center.set( 0, 0, 0 );
            sphere.radius = 0.7071067811865476;
            sphere.applyMatrix4( sprite.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 Vector3(),
            p2 = new Vector3();

        return function intersectsBox( 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;

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {

    var _gl = _renderer.context,
        _state = _renderer.state,
        _frustum = new Frustum(),
        _projScreenMatrix = new Matrix4(),

        _lightShadows = _lights.shadows,

        _shadowMapSize = new Vector2(),
        _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ),

        _lookTarget = new Vector3(),
        _lightPositionWorld = new Vector3(),

        _MorphingFlag = 1,
        _SkinningFlag = 2,

        _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,

        _depthMaterials = new Array( _NumberOfMaterialVariants ),
        _distanceMaterials = new Array( _NumberOfMaterialVariants ),

        _materialCache = {};

    var cubeDirections = [
        new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
        new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
    ];

    var cubeUps = [
        new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
        new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),    new Vector3( 0, 0, - 1 )
    ];

    var cube2DViewPorts = [
        new Vector4(), new Vector4(), new Vector4(),
        new Vector4(), new Vector4(), new Vector4()
    ];

    // init

    var depthMaterialTemplate = new MeshDepthMaterial();
    depthMaterialTemplate.depthPacking = RGBADepthPacking;
    depthMaterialTemplate.clipping = true;

    var distanceShader = ShaderLib[ "distanceRGBA" ];
    var distanceUniforms = UniformsUtils.clone( distanceShader.uniforms );

    for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {

        var useMorphing = ( i & _MorphingFlag ) !== 0;
        var useSkinning = ( i & _SkinningFlag ) !== 0;

        var depthMaterial = depthMaterialTemplate.clone();
        depthMaterial.morphTargets = useMorphing;
        depthMaterial.skinning = useSkinning;

        _depthMaterials[ i ] = depthMaterial;

        var distanceMaterial = new ShaderMaterial( {
            defines: {
                'USE_SHADOWMAP': ''
            },
            uniforms: distanceUniforms,
            vertexShader: distanceShader.vertexShader,
            fragmentShader: distanceShader.fragmentShader,
            morphTargets: useMorphing,
            skinning: useSkinning,
            clipping: true
        } );

        _distanceMaterials[ i ] = distanceMaterial;

    }

    //

    var scope = this;

    this.enabled = false;

    this.autoUpdate = true;
    this.needsUpdate = false;

    this.type = PCFShadowMap;

    this.renderReverseSided = true;
    this.renderSingleSided = true;

    this.render = function ( scene, camera ) {

        if ( scope.enabled === false ) return;
        if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;

        if ( _lightShadows.length === 0 ) return;

        // Set GL state for depth map.
        _state.disable( _gl.BLEND );
        _state.buffers.color.setClear( 1, 1, 1, 1 );
        _state.buffers.depth.setTest( true );
        _state.setScissorTest( false );

        // render depth map

        var faceCount;

        for ( var i = 0, il = _lightShadows.length; i < il; i ++ ) {

            var light = _lightShadows[ i ];
            var shadow = light.shadow;
            var isPointLight = light && light.isPointLight;

            if ( shadow === undefined ) {

                console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
                continue;

            }

            var shadowCamera = shadow.camera;

            _shadowMapSize.copy( shadow.mapSize );
            _shadowMapSize.min( _maxShadowMapSize );

            if ( isPointLight ) {

                var vpWidth = _shadowMapSize.x;
                var vpHeight = _shadowMapSize.y;

                // These viewports map a cube-map onto a 2D texture with the
                // following orientation:
                //
                //  xzXZ
                //   y Y
                //
                // X - Positive x direction
                // x - Negative x direction
                // Y - Positive y direction
                // y - Negative y direction
                // Z - Positive z direction
                // z - Negative z direction

                // positive X
                cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
                // negative X
                cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
                // positive Z
                cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
                // negative Z
                cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
                // positive Y
                cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
                // negative Y
                cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );

                _shadowMapSize.x *= 4.0;
                _shadowMapSize.y *= 2.0;

            }

            if ( shadow.map === null ) {

                var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };

                shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
                shadow.map.texture.name = light.name + ".shadowMap";

                shadowCamera.updateProjectionMatrix();

            }

            if ( shadow.isSpotLightShadow ) {

                shadow.update( light );

            }

            var shadowMap = shadow.map;
            var shadowMatrix = shadow.matrix;

            _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
            shadowCamera.position.copy( _lightPositionWorld );

            if ( isPointLight ) {

                faceCount = 6;

                // for point lights we set the shadow matrix to be a translation-only matrix
                // equal to inverse of the light's position

                shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );

            } else {

                faceCount = 1;

                _lookTarget.setFromMatrixPosition( light.target.matrixWorld );
                shadowCamera.lookAt( _lookTarget );
                shadowCamera.updateMatrixWorld();

                // 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 );

            }

            _renderer.setRenderTarget( shadowMap );
            _renderer.clear();

            // render shadow map for each cube face (if omni-directional) or
            // run a single pass if not

            for ( var face = 0; face < faceCount; face ++ ) {

                if ( isPointLight ) {

                    _lookTarget.copy( shadowCamera.position );
                    _lookTarget.add( cubeDirections[ face ] );
                    shadowCamera.up.copy( cubeUps[ face ] );
                    shadowCamera.lookAt( _lookTarget );
                    shadowCamera.updateMatrixWorld();

                    var vpDimensions = cube2DViewPorts[ face ];
                    _state.viewport( vpDimensions );

                }

                // update camera matrices and frustum

                _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
                _frustum.setFromMatrix( _projScreenMatrix );

                // set object matrices & frustum culling

                renderObject( scene, camera, shadowCamera, isPointLight );

            }

        }

        // Restore GL state.
        var clearColor = _renderer.getClearColor();
        var clearAlpha = _renderer.getClearAlpha();
        _renderer.setClearColor( clearColor, clearAlpha );

        scope.needsUpdate = false;

    };

    function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {

        var geometry = object.geometry;

        var result = null;

        var materialVariants = _depthMaterials;
        var customMaterial = object.customDepthMaterial;

        if ( isPointLight ) {

            materialVariants = _distanceMaterials;
            customMaterial = object.customDistanceMaterial;

        }

        if ( ! customMaterial ) {

            var useMorphing = false;

            if ( material.morphTargets ) {

                if ( geometry && geometry.isBufferGeometry ) {

                    useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;

                } else if ( geometry && geometry.isGeometry ) {

                    useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;

                }

            }

            if ( object.isSkinnedMesh && material.skinning === false ) {

                console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );

            }

            var useSkinning = object.isSkinnedMesh && material.skinning;

            var variantIndex = 0;

            if ( useMorphing ) variantIndex |= _MorphingFlag;
            if ( useSkinning ) variantIndex |= _SkinningFlag;

            result = materialVariants[ variantIndex ];

        } else {

            result = customMaterial;

        }

        if ( _renderer.localClippingEnabled &&
                material.clipShadows === true &&
                material.clippingPlanes.length !== 0 ) {

            // in this case we need a unique material instance reflecting the
            // appropriate state

            var keyA = result.uuid, keyB = material.uuid;

            var materialsForVariant = _materialCache[ keyA ];

            if ( materialsForVariant === undefined ) {

                materialsForVariant = {};
                _materialCache[ keyA ] = materialsForVariant;

            }

            var cachedMaterial = materialsForVariant[ keyB ];

            if ( cachedMaterial === undefined ) {

                cachedMaterial = result.clone();
                materialsForVariant[ keyB ] = cachedMaterial;

            }

            result = cachedMaterial;

        }

        result.visible = material.visible;
        result.wireframe = material.wireframe;

        var side = material.side;

        if ( scope.renderSingleSided && side == DoubleSide ) {

            side = FrontSide;

        }

        if ( scope.renderReverseSided ) {

            if ( side === FrontSide ) side = BackSide;
            else if ( side === BackSide ) side = FrontSide;

        }

        result.side = side;

        result.clipShadows = material.clipShadows;
        result.clippingPlanes = material.clippingPlanes;

        result.wireframeLinewidth = material.wireframeLinewidth;
        result.linewidth = material.linewidth;

        if ( isPointLight && result.uniforms.lightPos !== undefined ) {

            result.uniforms.lightPos.value.copy( lightPositionWorld );

        }

        return result;

    }

    function renderObject( object, camera, shadowCamera, isPointLight ) {

        if ( object.visible === false ) return;

        var visible = object.layers.test( camera.layers );

        if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {

            if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {

                object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

                var geometry = _objects.update( object );
                var material = object.material;

                if ( Array.isArray( material ) ) {

                    var groups = geometry.groups;

                    for ( var k = 0, kl = groups.length; k < kl; k ++ ) {

                        var group = groups[ k ];
                        var groupMaterial = material[ group.materialIndex ];

                        if ( groupMaterial && groupMaterial.visible ) {

                            var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
                            _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );

                        }

                    }

                } else if ( material.visible ) {

                    var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
                    _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );

                }

            }

        }

        var children = object.children;

        for ( var i = 0, l = children.length; i < l; i ++ ) {

            renderObject( children[ i ], camera, shadowCamera, isPointLight );

        }

    }

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLAttributes( gl ) {

    var buffers = {};

    function createBuffer( attribute, bufferType ) {

        var array = attribute.array;
        var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;

        var buffer = gl.createBuffer();

        gl.bindBuffer( bufferType, buffer );
        gl.bufferData( bufferType, array, usage );

        attribute.onUploadCallback();

        var type = gl.FLOAT;

        if ( array instanceof Float32Array ) {

            type = gl.FLOAT;

        } else if ( array instanceof Float64Array ) {

            console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );

        } else if ( array instanceof Uint16Array ) {

            type = gl.UNSIGNED_SHORT;

        } else if ( array instanceof Int16Array ) {

            type = gl.SHORT;

        } else if ( array instanceof Uint32Array ) {

            type = gl.UNSIGNED_INT;

        } else if ( array instanceof Int32Array ) {

            type = gl.INT;

        } else if ( array instanceof Int8Array ) {

            type = gl.BYTE;

        } else if ( array instanceof Uint8Array ) {

            type = gl.UNSIGNED_BYTE;

        }

        return {
            buffer: buffer,
            type: type,
            bytesPerElement: array.BYTES_PER_ELEMENT,
            version: attribute.version
        };

    }

    function updateBuffer( buffer, attribute, bufferType ) {

        var array = attribute.array;
        var updateRange = attribute.updateRange;

        gl.bindBuffer( bufferType, buffer );

        if ( attribute.dynamic === false ) {

            gl.bufferData( bufferType, array, gl.STATIC_DRAW );

        } else if ( updateRange.count === - 1 ) {

            // Not using update ranges

            gl.bufferSubData( bufferType, 0, array );

        } else if ( updateRange.count === 0 ) {

            console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );

        } else {

            gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
                array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );

            updateRange.count = -1; // reset range

        }

    }

    //

    function get( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        return buffers[ attribute.uuid ];

    }

    function remove( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
        
        var data = buffers[ attribute.uuid ];

        if ( data ) {

            gl.deleteBuffer( data.buffer );

            delete buffers[ attribute.uuid ];

        }

    }

    function update( attribute, bufferType ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        var data = buffers[ attribute.uuid ];

        if ( data === undefined ) {

            buffers[ attribute.uuid ] = createBuffer( attribute, bufferType );

        } else if ( data.version < attribute.version ) {

            updateBuffer( data.buffer, attribute, bufferType );

            data.version = attribute.version;

        }

    }

    return {

        get: get,
        remove: remove,
        update: update

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://clara.io
 */

function Euler( x, y, z, order ) {

    this._x = x || 0;
    this._y = y || 0;
    this._z = z || 0;
    this._order = order || Euler.DefaultOrder;

}

Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];

Euler.DefaultOrder = 'XYZ';

Object.defineProperties( Euler.prototype, {

    x: {

        get: function () {

            return this._x;

        },

        set: function ( value ) {

            this._x = value;
            this.onChangeCallback();

        }

    },

    y: {

        get: function () {

            return this._y;

        },

        set: function ( value ) {

            this._y = value;
            this.onChangeCallback();

        }

    },

    z: {

        get: function () {

            return this._z;

        },

        set: function ( value ) {

            this._z = value;
            this.onChangeCallback();

        }

    },

    order: {

        get: function () {

            return this._order;

        },

        set: function ( value ) {

            this._order = value;
            this.onChangeCallback();

        }

    }

} );

Object.assign( Euler.prototype, {

    isEuler: true,

    set: function ( x, y, z, order ) {

        this._x = x;
        this._y = y;
        this._z = z;
        this._order = order || this._order;

        this.onChangeCallback();

        return this;

    },

    clone: function () {

        return new this.constructor( this._x, this._y, this._z, this._order );

    },

    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 = _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 {

            console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );

        }

        this._order = order;

        if ( update !== false ) this.onChangeCallback();

        return this;

    },

    setFromQuaternion: function () {

        var matrix = new Matrix4();

        return function setFromQuaternion( q, order, update ) {

            matrix.makeRotationFromQuaternion( q );

            return this.setFromRotationMatrix( matrix, order, update );

        };

    }(),

    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 Quaternion();

        return function reorder( newOrder ) {

            q.setFromEuler( this );

            return 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 Vector3( this._x, this._y, this._z );

        }

    },

    onChange: function ( callback ) {

        this.onChangeCallback = callback;

        return this;

    },

    onChangeCallback: function () {}

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Layers() {

    this.mask = 1 | 0;

}

Object.assign( Layers.prototype, {

    set: function ( channel ) {

        this.mask = 1 << channel | 0;

    },

    enable: function ( channel ) {

        this.mask |= 1 << channel | 0;

    },

    toggle: function ( channel ) {

        this.mask ^= 1 << channel | 0;

    },

    disable: function ( channel ) {

        this.mask &= ~ ( 1 << channel | 0 );

    },

    test: function ( layers ) {

        return ( this.mask & layers.mask ) !== 0;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author elephantatwork / www.elephantatwork.ch
 */

var object3DId = 0;

function Object3D() {

    Object.defineProperty( this, 'id', { value: object3DId ++ } );

    this.uuid = _Math.generateUUID();

    this.name = '';
    this.type = 'Object3D';

    this.parent = null;
    this.children = [];

    this.up = Object3D.DefaultUp.clone();

    var position = new Vector3();
    var rotation = new Euler();
    var quaternion = new Quaternion();
    var scale = new Vector3( 1, 1, 1 );

    function onRotationChange() {

        quaternion.setFromEuler( rotation, false );

    }

    function onQuaternionChange() {

        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
        },
        modelViewMatrix: {
            value: new Matrix4()
        },
        normalMatrix: {
            value: new Matrix3()
        }
    } );

    this.matrix = new Matrix4();
    this.matrixWorld = new Matrix4();

    this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
    this.matrixWorldNeedsUpdate = false;

    this.layers = new Layers();
    this.visible = true;

    this.castShadow = false;
    this.receiveShadow = false;

    this.frustumCulled = true;
    this.renderOrder = 0;

    this.userData = {};
}

Object3D.DefaultUp = new Vector3( 0, 1, 0 );
Object3D.DefaultMatrixAutoUpdate = true;

Object.assign( Object3D.prototype, EventDispatcher.prototype, {

    isObject3D: true,

    onBeforeRender: function () {},
    onAfterRender: function () {},

    applyMatrix: function ( matrix ) {

        this.matrix.multiplyMatrices( matrix, this.matrix );

        this.matrix.decompose( this.position, this.quaternion, this.scale );

    },

    applyQuaternion: function ( q ) {

        this.quaternion.premultiply( q );

        return this;

    },

    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 Quaternion();

        return function rotateOnAxis( axis, angle ) {

            q1.setFromAxisAngle( axis, angle );

            this.quaternion.multiply( q1 );

            return this;

        };

    }(),

    rotateX: function () {

        var v1 = new Vector3( 1, 0, 0 );

        return function rotateX( angle ) {

            return this.rotateOnAxis( v1, angle );

        };

    }(),

    rotateY: function () {

        var v1 = new Vector3( 0, 1, 0 );

        return function rotateY( angle ) {

            return this.rotateOnAxis( v1, angle );

        };

    }(),

    rotateZ: function () {

        var v1 = new Vector3( 0, 0, 1 );

        return function rotateZ( 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 Vector3();

        return function translateOnAxis( axis, distance ) {

            v1.copy( axis ).applyQuaternion( this.quaternion );

            this.position.add( v1.multiplyScalar( distance ) );

            return this;

        };

    }(),

    translateX: function () {

        var v1 = new Vector3( 1, 0, 0 );

        return function translateX( distance ) {

            return this.translateOnAxis( v1, distance );

        };

    }(),

    translateY: function () {

        var v1 = new Vector3( 0, 1, 0 );

        return function translateY( distance ) {

            return this.translateOnAxis( v1, distance );

        };

    }(),

    translateZ: function () {

        var v1 = new Vector3( 0, 0, 1 );

        return function translateZ( distance ) {

            return this.translateOnAxis( v1, distance );

        };

    }(),

    localToWorld: function ( vector ) {

        return vector.applyMatrix4( this.matrixWorld );

    },

    worldToLocal: function () {

        var m1 = new Matrix4();

        return function worldToLocal( vector ) {

            return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );

        };

    }(),

    lookAt: function () {

        // This method does not support objects with rotated and/or translated parent(s)

        var m1 = new Matrix4();

        return function lookAt( vector ) {

            if ( this.isCamera ) {

                m1.lookAt( this.position, vector, this.up );

            } else {

                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 ) {

            console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
            return this;

        }

        if ( ( object && object.isObject3D ) ) {

            if ( object.parent !== null ) {

                object.parent.remove( object );

            }

            object.parent = this;
            object.dispatchEvent( { type: 'added' } );

            this.children.push( object );

        } else {

            console.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 ] );

            }

            return this;

        }

        var index = this.children.indexOf( object );

        if ( index !== - 1 ) {

            object.parent = null;

            object.dispatchEvent( { type: 'removed' } );

            this.children.splice( index, 1 );

        }

        return this;
        
    },

    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 Vector3();

        this.updateMatrixWorld( true );

        return result.setFromMatrixPosition( this.matrixWorld );

    },

    getWorldQuaternion: function () {

        var position = new Vector3();
        var scale = new Vector3();

        return function getWorldQuaternion( optionalTarget ) {

            var result = optionalTarget || new Quaternion();

            this.updateMatrixWorld( true );

            this.matrixWorld.decompose( position, result, scale );

            return result;

        };

    }(),

    getWorldRotation: function () {

        var quaternion = new Quaternion();

        return function getWorldRotation( optionalTarget ) {

            var result = optionalTarget || new Euler();

            this.getWorldQuaternion( quaternion );

            return result.setFromQuaternion( quaternion, this.rotation.order, false );

        };

    }(),

    getWorldScale: function () {

        var position = new Vector3();
        var quaternion = new Quaternion();

        return function getWorldScale( optionalTarget ) {

            var result = optionalTarget || new Vector3();

            this.updateMatrixWorld( true );

            this.matrixWorld.decompose( position, quaternion, result );

            return result;

        };

    }(),

    getWorldDirection: function () {

        var quaternion = new Quaternion();

        return function getWorldDirection( optionalTarget ) {

            var result = optionalTarget || new Vector3();

            this.getWorldQuaternion( quaternion );

            return result.set( 0, 0, 1 ).applyQuaternion( quaternion );

        };

    }(),

    raycast: function () {},

    traverse: function ( callback ) {

        callback( this );

        var children = this.children;

        for ( var i = 0, l = children.length; i < l; i ++ ) {

            children[ i ].traverse( callback );

        }

    },

    traverseVisible: function ( callback ) {

        if ( this.visible === false ) return;

        callback( this );

        var children = this.children;

        for ( var i = 0, l = children.length; i < l; i ++ ) {

            children[ i ].traverseVisible( callback );

        }

    },

    traverseAncestors: function ( callback ) {

        var parent = this.parent;

        if ( parent !== null ) {

            callback( parent );

            parent.traverseAncestors( callback );

        }

    },

    updateMatrix: function () {

        this.matrix.compose( this.position, this.quaternion, this.scale );

        this.matrixWorldNeedsUpdate = true;

    },

    updateMatrixWorld: function ( force ) {

        if ( this.matrixAutoUpdate ) this.updateMatrix();

        if ( this.matrixWorldNeedsUpdate || force ) {

            if ( this.parent === null ) {

                this.matrixWorld.copy( this.matrix );

            } else {

                this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );

            }

            this.matrixWorldNeedsUpdate = false;

            force = true;

        }

        // update children

        var children = this.children;

        for ( var i = 0, l = children.length; i < l; i ++ ) {

            children[ i ].updateMatrixWorld( force );

        }

    },

    toJSON: function ( meta ) {

        // meta is '' when called from JSON.stringify
        var isRootObject = ( meta === undefined || meta === '' );

        var output = {};

        // meta is a hash used to collect geometries, materials.
        // not providing it implies that this is the root object
        // being serialized.
        if ( isRootObject ) {

            // initialize meta obj
            meta = {
                geometries: {},
                materials: {},
                textures: {},
                images: {}
            };

            output.metadata = {
                version: 4.5,
                type: 'Object',
                generator: 'Object3D.toJSON'
            };

        }

        // standard Object3D serialization

        var object = {};

        object.uuid = this.uuid;
        object.type = this.type;

        if ( this.name !== '' ) object.name = this.name;
        if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
        if ( this.castShadow === true ) object.castShadow = true;
        if ( this.receiveShadow === true ) object.receiveShadow = true;
        if ( this.visible === false ) object.visible = false;

        object.matrix = this.matrix.toArray();

        //

        function serialize( library, element ) {

            if ( library[ element.uuid ] === undefined ) {

                library[ element.uuid ] = element.toJSON( meta );

            }

            return element.uuid;

        }

        if ( this.geometry !== undefined ) {

            object.geometry = serialize( meta.geometries, this.geometry );

        }

        if ( this.material !== undefined ) {

            if ( Array.isArray( this.material ) ) {

                var uuids = [];

                for ( var i = 0, l = this.material.length; i < l; i ++ ) {

                    uuids.push( serialize( meta.materials, this.material[ i ] ) );

                }

                object.material = uuids;

            } else {

                object.material = serialize( meta.materials, this.material );

            }

        }

        //

        if ( this.children.length > 0 ) {

            object.children = [];

            for ( var i = 0; i < this.children.length; i ++ ) {

                object.children.push( this.children[ i ].toJSON( meta ).object );

            }

        }

        if ( isRootObject ) {

            var geometries = extractFromCache( meta.geometries );
            var materials = extractFromCache( meta.materials );
            var textures = extractFromCache( meta.textures );
            var images = extractFromCache( meta.images );

            if ( geometries.length > 0 ) output.geometries = geometries;
            if ( materials.length > 0 ) output.materials = materials;
            if ( textures.length > 0 ) output.textures = textures;
            if ( images.length > 0 ) output.images = images;

        }

        output.object = object;

        return output;

        // extract data from the cache hash
        // remove metadata on each item
        // and return as array
        function extractFromCache( cache ) {

            var values = [];
            for ( var key in cache ) {

                var data = cache[ key ];
                delete data.metadata;
                values.push( data );

            }
            return values;

        }

    },

    clone: function ( recursive ) {

        return new this.constructor().copy( this, recursive );

    },

    copy: function ( source, recursive ) {

        if ( recursive === undefined ) recursive = true;

        this.name = source.name;

        this.up.copy( source.up );

        this.position.copy( source.position );
        this.quaternion.copy( source.quaternion );
        this.scale.copy( source.scale );

        this.matrix.copy( source.matrix );
        this.matrixWorld.copy( source.matrixWorld );

        this.matrixAutoUpdate = source.matrixAutoUpdate;
        this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

        this.layers.mask = source.layers.mask;
        this.visible = source.visible;

        this.castShadow = source.castShadow;
        this.receiveShadow = source.receiveShadow;

        this.frustumCulled = source.frustumCulled;
        this.renderOrder = source.renderOrder;

        this.userData = JSON.parse( JSON.stringify( source.userData ) );

        if ( recursive === true ) {

            for ( var i = 0; i < source.children.length; i ++ ) {

                var child = source.children[ i ];
                this.add( child.clone() );

            }

        }

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author WestLangley / http://github.com/WestLangley
*/

function Camera() {

    Object3D.call( this );

    this.type = 'Camera';

    this.matrixWorldInverse = new Matrix4();
    this.projectionMatrix = new Matrix4();

}

Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Camera,

    isCamera: true,

    copy: function ( source, recursive ) {

        Object3D.prototype.copy.call( this, source, recursive );

        this.matrixWorldInverse.copy( source.matrixWorldInverse );
        this.projectionMatrix.copy( source.projectionMatrix );

        return this;

    },

    getWorldDirection: function () {

        var quaternion = new Quaternion();

        return function getWorldDirection( optionalTarget ) {

            var result = optionalTarget || new Vector3();

            this.getWorldQuaternion( quaternion );

            return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );

        };

    }(),

    updateMatrixWorld: function ( force ) {

        Object3D.prototype.updateMatrixWorld.call( this, force );

        this.matrixWorldInverse.getInverse( this.matrixWorld );

    },

    clone: function () {

        return new this.constructor().copy( this );

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 * @author arose / http://github.com/arose
 */

function OrthographicCamera( left, right, top, bottom, near, far ) {

    Camera.call( this );

    this.type = 'OrthographicCamera';

    this.zoom = 1;
    this.view = null;

    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();

}

OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {

    constructor: OrthographicCamera,

    isOrthographicCamera: true,

    copy: function ( source, recursive ) {

        Camera.prototype.copy.call( this, source, recursive );

        this.left = source.left;
        this.right = source.right;
        this.top = source.top;
        this.bottom = source.bottom;
        this.near = source.near;
        this.far = source.far;

        this.zoom = source.zoom;
        this.view = source.view === null ? null : Object.assign( {}, source.view );

        return this;

    },

    setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {

        this.view = {
            fullWidth: fullWidth,
            fullHeight: fullHeight,
            offsetX: x,
            offsetY: y,
            width: width,
            height: height
        };

        this.updateProjectionMatrix();

    },

    clearViewOffset: function() {

        this.view = null;
        this.updateProjectionMatrix();

    },

    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;

        var left = cx - dx;
        var right = cx + dx;
        var top = cy + dy;
        var bottom = cy - dy;

        if ( this.view !== null ) {

            var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
            var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
            var scaleW = ( this.right - this.left ) / this.view.width;
            var scaleH = ( this.top - this.bottom ) / this.view.height;

            left += scaleW * ( this.view.offsetX / zoomW );
            right = left + scaleW * ( this.view.width / zoomW );
            top -= scaleH * ( this.view.offsetY / zoomH );
            bottom = top - scaleH * ( this.view.height / zoomH );

        }

        this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );

    },

    toJSON: function ( meta ) {

        var data = Object3D.prototype.toJSON.call( this, meta );

        data.object.zoom = this.zoom;
        data.object.left = this.left;
        data.object.right = this.right;
        data.object.top = this.top;
        data.object.bottom = this.bottom;
        data.object.near = this.near;
        data.object.far = this.far;

        if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );

        return data;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author greggman / http://games.greggman.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * @author tschw
 */

function PerspectiveCamera( fov, aspect, near, far ) {

    Camera.call( this );

    this.type = 'PerspectiveCamera';

    this.fov = fov !== undefined ? fov : 50;
    this.zoom = 1;

    this.near = near !== undefined ? near : 0.1;
    this.far = far !== undefined ? far : 2000;
    this.focus = 10;

    this.aspect = aspect !== undefined ? aspect : 1;
    this.view = null;

    this.filmGauge = 35;    // width of the film (default in millimeters)
    this.filmOffset = 0;    // horizontal film offset (same unit as gauge)

    this.updateProjectionMatrix();

}

PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {

    constructor: PerspectiveCamera,

    isPerspectiveCamera: true,

    copy: function ( source, recursive ) {

        Camera.prototype.copy.call( this, source, recursive );

        this.fov = source.fov;
        this.zoom = source.zoom;

        this.near = source.near;
        this.far = source.far;
        this.focus = source.focus;

        this.aspect = source.aspect;
        this.view = source.view === null ? null : Object.assign( {}, source.view );

        this.filmGauge = source.filmGauge;
        this.filmOffset = source.filmOffset;

        return this;

    },

    /**
     * Sets the FOV by focal length in respect to the current .filmGauge.
     *
     * The default film gauge is 35, so that the focal length can be specified for
     * a 35mm (full frame) camera.
     *
     * Values for focal length and film gauge must have the same unit.
     */
    setFocalLength: function ( focalLength ) {

        // see http://www.bobatkins.com/photography/technical/field_of_view.html
        var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;

        this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
        this.updateProjectionMatrix();

    },

    /**
     * Calculates the focal length from the current .fov and .filmGauge.
     */
    getFocalLength: function () {

        var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );

        return 0.5 * this.getFilmHeight() / vExtentSlope;

    },

    getEffectiveFOV: function () {

        return _Math.RAD2DEG * 2 * Math.atan(
                Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );

    },

    getFilmWidth: function () {

        // film not completely covered in portrait format (aspect < 1)
        return this.filmGauge * Math.min( this.aspect, 1 );

    },

    getFilmHeight: function () {

        // film not completely covered in landscape format (aspect > 1)
        return this.filmGauge / Math.max( this.aspect, 1 );

    },

    /**
     * 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.
     */
    setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {

        this.aspect = fullWidth / fullHeight;

        this.view = {
            fullWidth: fullWidth,
            fullHeight: fullHeight,
            offsetX: x,
            offsetY: y,
            width: width,
            height: height
        };

        this.updateProjectionMatrix();

    },

    clearViewOffset: function () {

        this.view = null;
        this.updateProjectionMatrix();

    },

    updateProjectionMatrix: function () {

        var near = this.near,
            top = near * Math.tan(
                    _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
            height = 2 * top,
            width = this.aspect * height,
            left = - 0.5 * width,
            view = this.view;

        if ( view !== null ) {

            var fullWidth = view.fullWidth,
                fullHeight = view.fullHeight;

            left += view.offsetX * width / fullWidth;
            top -= view.offsetY * height / fullHeight;
            width *= view.width / fullWidth;
            height *= view.height / fullHeight;

        }

        var skew = this.filmOffset;
        if ( skew !== 0 ) left += near * skew / this.getFilmWidth();

        this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );

    },

    toJSON: function ( meta ) {

        var data = Object3D.prototype.toJSON.call( this, meta );

        data.object.fov = this.fov;
        data.object.zoom = this.zoom;

        data.object.near = this.near;
        data.object.far = this.far;
        data.object.focus = this.focus;

        data.object.aspect = this.aspect;

        if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );

        data.object.filmGauge = this.filmGauge;
        data.object.filmOffset = this.filmOffset;

        return data;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function Face3( a, b, c, normal, color, materialIndex ) {

    this.a = a;
    this.b = b;
    this.c = c;

    this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
    this.vertexNormals = Array.isArray( normal ) ? normal : [];

    this.color = ( color && color.isColor ) ? color : new Color();
    this.vertexColors = Array.isArray( color ) ? color : [];

    this.materialIndex = materialIndex !== undefined ? materialIndex : 0;

}

Object.assign( Face3.prototype, {

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( source ) {

        this.a = source.a;
        this.b = source.b;
        this.c = source.c;

        this.normal.copy( source.normal );
        this.color.copy( source.color );

        this.materialIndex = source.materialIndex;

        for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {

            this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();

        }

        for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {

            this.vertexColors[ i ] = source.vertexColors[ i ].clone();

        }

        return this;

    }

} );

/**
 * @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://clara.io
 */

var count = 0;
function GeometryIdCount() { return count++; }

function Geometry() {

    Object.defineProperty( this, 'id', { value: GeometryIdCount() } );

    this.uuid = _Math.generateUUID();

    this.name = '';
    this.type = 'Geometry';

    this.vertices = [];
    this.colors = [];
    this.faces = [];
    this.faceVertexUvs = [[]];

    this.morphTargets = [];
    this.morphNormals = [];

    this.skinWeights = [];
    this.skinIndices = [];

    this.lineDistances = [];

    this.boundingBox = null;
    this.boundingSphere = null;

    // update flags

    this.elementsNeedUpdate = false;
    this.verticesNeedUpdate = false;
    this.uvsNeedUpdate = false;
    this.normalsNeedUpdate = false;
    this.colorsNeedUpdate = false;
    this.lineDistancesNeedUpdate = false;
    this.groupsNeedUpdate = false;

}

Object.assign( Geometry.prototype, EventDispatcher.prototype, {

    isGeometry: true,

    applyMatrix: function ( matrix ) {

        var normalMatrix = new 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;

        return this;

    },

    rotateX: function () {

        // rotate geometry around world x-axis

        var m1 = new Matrix4();

        return function rotateX( angle ) {

            m1.makeRotationX( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    rotateY: function () {

        // rotate geometry around world y-axis

        var m1 = new Matrix4();

        return function rotateY( angle ) {

            m1.makeRotationY( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    rotateZ: function () {

        // rotate geometry around world z-axis

        var m1 = new Matrix4();

        return function rotateZ( angle ) {

            m1.makeRotationZ( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    translate: function () {

        // translate geometry

        var m1 = new Matrix4();

        return function translate( x, y, z ) {

            m1.makeTranslation( x, y, z );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    scale: function () {

        // scale geometry

        var m1 = new Matrix4();

        return function scale( x, y, z ) {

            m1.makeScale( x, y, z );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    lookAt: function () {

        var obj = new Object3D();

        return function lookAt( vector ) {

            obj.lookAt( vector );

            obj.updateMatrix();

            this.applyMatrix( obj.matrix );

        };

    }(),

    fromBufferGeometry: function ( geometry ) {

        var scope = this;

        var indices = geometry.index !== null ? geometry.index.array : undefined;
        var attributes = geometry.attributes;

        var positions = attributes.position.array;
        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 uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;

        if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];

        var tempNormals = [];
        var tempUVs = [];
        var tempUVs2 = [];

        for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {

            scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );

            if ( normals !== undefined ) {

                tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );

            }

            if ( colors !== undefined ) {

                scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );

            }

            if ( uvs !== undefined ) {

                tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );

            }

            if ( uvs2 !== undefined ) {

                tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );

            }

        }

        function addFace( a, b, c, materialIndex ) {

            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() ] : [];

            var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );

            scope.faces.push( face );

            if ( uvs !== undefined ) {

                scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );

            }

            if ( uvs2 !== undefined ) {

                scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );

            }

        }

        var groups = geometry.groups;

        if ( groups.length > 0 ) {

            for ( var i = 0; i < groups.length; i ++ ) {

                var group = groups[ i ];

                var start = group.start;
                var count = group.count;

                for ( var j = start, jl = start + count; j < jl; j += 3 ) {

                    if ( indices !== undefined ) {

                        addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );

                    } else {

                        addFace( j, j + 1, j + 2, group.materialIndex );

                    }

                }

            }

        } else {

            if ( indices !== undefined ) {

                for ( var i = 0; i < indices.length; i += 3 ) {

                    addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );

                }

            } else {

                for ( var i = 0; i < positions.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.getCenter().negate();

        this.translate( offset.x, offset.y, offset.z );

        return offset;

    },

    normalize: function () {

        this.computeBoundingSphere();

        var center = this.boundingSphere.center;
        var radius = this.boundingSphere.radius;

        var s = radius === 0 ? 1 : 1.0 / radius;

        var matrix = new Matrix4();
        matrix.set(
            s, 0, 0, - s * center.x,
            0, s, 0, - s * center.y,
            0, 0, s, - s * center.z,
            0, 0, 0, 1
        );

        this.applyMatrix( matrix );

        return this;

    },

    computeFaceNormals: function () {

        var cb = new Vector3(), ab = new 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 ) {

        if ( areaWeighted === undefined ) areaWeighted = true;

        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 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 Vector3(), ab = new 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 {

            this.computeFaceNormals();

            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 ];

            var vertexNormals = face.vertexNormals;

            if ( vertexNormals.length === 3 ) {

                vertexNormals[ 0 ].copy( vertices[ face.a ] );
                vertexNormals[ 1 ].copy( vertices[ face.b ] );
                vertexNormals[ 2 ].copy( vertices[ face.c ] );

            } else {

                vertexNormals[ 0 ] = vertices[ face.a ].clone();
                vertexNormals[ 1 ] = vertices[ face.b ].clone();
                vertexNormals[ 2 ] = vertices[ face.c ].clone();

            }

        }

        if ( this.faces.length > 0 ) {

            this.normalsNeedUpdate = true;

        }

    },

    computeFlatVertexNormals: function () {

        var f, fl, face;

        this.computeFaceNormals();

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            var vertexNormals = face.vertexNormals;

            if ( vertexNormals.length === 3 ) {

                vertexNormals[ 0 ].copy( face.normal );
                vertexNormals[ 1 ].copy( face.normal );
                vertexNormals[ 2 ].copy( face.normal );

            } else {

                vertexNormals[ 0 ] = face.normal.clone();
                vertexNormals[ 1 ] = face.normal.clone();
                vertexNormals[ 2 ] = face.normal.clone();

            }

        }

        if ( this.faces.length > 0 ) {

            this.normalsNeedUpdate = true;

        }

    },

    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 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 Vector3();
                    vertexNormals = { a: new Vector3(), b: new Vector3(), c: new 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;

        }

    },

    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 Box3();

        }

        this.boundingBox.setFromPoints( this.vertices );

    },

    computeBoundingSphere: function () {

        if ( this.boundingSphere === null ) {

            this.boundingSphere = new Sphere();

        }

        this.boundingSphere.setFromPoints( this.vertices );

    },

    merge: function ( geometry, matrix, materialIndexOffset ) {

        if ( ! ( geometry && geometry.isGeometry ) ) {

            console.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 ],
            colors1 = this.colors,
            colors2 = geometry.colors;

        if ( materialIndexOffset === undefined ) materialIndexOffset = 0;

        if ( matrix !== undefined ) {

            normalMatrix = new 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 );

        }

        // colors

        for ( var i = 0, il = colors2.length; i < il; i ++ ) {

            colors1.push( colors2[ i ].clone() );

        }

        // 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 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 && mesh.isMesh ) ) {

            console.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 vertices by position coordinates (and making sure they are unique)
        var unique = [], changes = [];

        var v, key;
        var precisionPoints = 4; // number of decimal points, e.g. 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 ];

            // 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 ] ) {

                    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;

    },

    sortFacesByMaterialIndex: function () {

        var faces = this.faces;
        var length = faces.length;

        // tag faces

        for ( var i = 0; i < length; i ++ ) {

            faces[ i ]._id = i;

        }

        // sort faces

        function materialIndexSort( a, b ) {

            return a.materialIndex - b.materialIndex;

        }

        faces.sort( materialIndexSort );

        // sort uvs

        var uvs1 = this.faceVertexUvs[ 0 ];
        var uvs2 = this.faceVertexUvs[ 1 ];

        var newUvs1, newUvs2;

        if ( uvs1 && uvs1.length === length ) newUvs1 = [];
        if ( uvs2 && uvs2.length === length ) newUvs2 = [];

        for ( var i = 0; i < length; i ++ ) {

            var id = faces[ i ]._id;

            if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
            if ( newUvs2 ) newUvs2.push( uvs2[ id ] );

        }

        if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
        if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;

    },

    toJSON: function () {

        var data = {
            metadata: {
                version: 4.5,
                type: 'Geometry',
                generator: 'Geometry.toJSON'
            }
        };

        // standard Geometry serialization

        data.uuid = this.uuid;
        data.type = this.type;
        if ( this.name !== '' ) data.name = this.name;

        if ( this.parameters !== undefined ) {

            var parameters = this.parameters;

            for ( var key in parameters ) {

                if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];

            }

            return data;

        }

        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 = true;
            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 ); // isQuad
            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 );
            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 ];

        }

        data.data = {};

        data.data.vertices = vertices;
        data.data.normals = normals;
        if ( colors.length > 0 ) data.data.colors = colors;
        if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
        data.data.faces = faces;

        return data;

    },

    clone: function () {

        /*
         // Handle primitives

         var parameters = this.parameters;

         if ( parameters !== undefined ) {

         var values = [];

         for ( var key in parameters ) {

         values.push( parameters[ key ] );

         }

         var geometry = Object.create( this.constructor.prototype );
         this.constructor.apply( geometry, values );
         return geometry;

         }

         return new this.constructor().copy( this );
         */

        return new Geometry().copy( this );

    },

    copy: function ( source ) {

        var i, il, j, jl, k, kl;

        // reset

        this.vertices = [];
        this.colors = [];
        this.faces = [];
        this.faceVertexUvs = [[]];
        this.morphTargets = [];
        this.morphNormals = [];
        this.skinWeights = [];
        this.skinIndices = [];
        this.lineDistances = [];
        this.boundingBox = null;
        this.boundingSphere = null;

        // name

        this.name = source.name;

        // vertices

        var vertices = source.vertices;

        for ( i = 0, il = vertices.length; i < il; i ++ ) {

            this.vertices.push( vertices[ i ].clone() );

        }

        // colors

        var colors = source.colors;

        for ( i = 0, il = colors.length; i < il; i ++ ) {

            this.colors.push( colors[ i ].clone() );

        }

        // faces

        var faces = source.faces;

        for ( i = 0, il = faces.length; i < il; i ++ ) {

            this.faces.push( faces[ i ].clone() );

        }

        // face vertex uvs

        for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {

            var faceVertexUvs = source.faceVertexUvs[ i ];

            if ( this.faceVertexUvs[ i ] === undefined ) {

                this.faceVertexUvs[ i ] = [];

            }

            for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {

                var uvs = faceVertexUvs[ j ], uvsCopy = [];

                for ( k = 0, kl = uvs.length; k < kl; k ++ ) {

                    var uv = uvs[ k ];

                    uvsCopy.push( uv.clone() );

                }

                this.faceVertexUvs[ i ].push( uvsCopy );

            }

        }

        // morph targets

        var morphTargets = source.morphTargets;

        for ( i = 0, il = morphTargets.length; i < il; i ++ ) {

            var morphTarget = {};
            morphTarget.name = morphTargets[ i ].name;

            // vertices

            if ( morphTargets[ i ].vertices !== undefined ) {

                morphTarget.vertices = [];

                for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {

                    morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );

                }

            }

            // normals

            if ( morphTargets[ i ].normals !== undefined ) {

                morphTarget.normals = [];

                for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {

                    morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );

                }

            }

            this.morphTargets.push( morphTarget );

        }

        // morph normals

        var morphNormals = source.morphNormals;

        for ( i = 0, il = morphNormals.length; i < il; i ++ ) {

            var morphNormal = {};

            // vertex normals

            if ( morphNormals[ i ].vertexNormals !== undefined ) {

                morphNormal.vertexNormals = [];

                for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {

                    var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
                    var destVertexNormal = {};

                    destVertexNormal.a = srcVertexNormal.a.clone();
                    destVertexNormal.b = srcVertexNormal.b.clone();
                    destVertexNormal.c = srcVertexNormal.c.clone();

                    morphNormal.vertexNormals.push( destVertexNormal );

                }

            }

            // face normals

            if ( morphNormals[ i ].faceNormals !== undefined ) {

                morphNormal.faceNormals = [];

                for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {

                    morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );

                }

            }

            this.morphNormals.push( morphNormal );

        }

        // skin weights

        var skinWeights = source.skinWeights;

        for ( i = 0, il = skinWeights.length; i < il; i ++ ) {

            this.skinWeights.push( skinWeights[ i ].clone() );

        }

        // skin indices

        var skinIndices = source.skinIndices;

        for ( i = 0, il = skinIndices.length; i < il; i ++ ) {

            this.skinIndices.push( skinIndices[ i ].clone() );

        }

        // line distances

        var lineDistances = source.lineDistances;

        for ( i = 0, il = lineDistances.length; i < il; i ++ ) {

            this.lineDistances.push( lineDistances[ i ] );

        }

        // bounding box

        var boundingBox = source.boundingBox;

        if ( boundingBox !== null ) {

            this.boundingBox = boundingBox.clone();

        }

        // bounding sphere

        var boundingSphere = source.boundingSphere;

        if ( boundingSphere !== null ) {

            this.boundingSphere = boundingSphere.clone();

        }

        // update flags

        this.elementsNeedUpdate = source.elementsNeedUpdate;
        this.verticesNeedUpdate = source.verticesNeedUpdate;
        this.uvsNeedUpdate = source.uvsNeedUpdate;
        this.normalsNeedUpdate = source.normalsNeedUpdate;
        this.colorsNeedUpdate = source.colorsNeedUpdate;
        this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
        this.groupsNeedUpdate = source.groupsNeedUpdate;

        return this;

    },

    dispose: function () {

        this.dispatchEvent( { type: 'dispose' } );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function BufferAttribute( array, itemSize, normalized ) {

    if ( Array.isArray( array ) ) {

        throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );

    }

    this.uuid = _Math.generateUUID();
    this.name = '';

    this.array = array;
    this.itemSize = itemSize;
    this.count = array !== undefined ? array.length / itemSize : 0;
    this.normalized = normalized === true;

    this.dynamic = false;
    this.updateRange = { offset: 0, count: - 1 };

    this.onUploadCallback = function () {};

    this.version = 0;

}

Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {

    set: function ( value ) {

        if ( value === true ) this.version ++;

    }

} );

Object.assign( BufferAttribute.prototype, {

    isBufferAttribute: true,

    setArray: function ( array ) {

        if ( Array.isArray( array ) ) {

            throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );

        }

        this.count = array !== undefined ? array.length / this.itemSize : 0;
        this.array = array;

    },

    setDynamic: function ( value ) {

        this.dynamic = value;

        return this;

    },

    copy: function ( source ) {

        this.array = new source.array.constructor( source.array );
        this.itemSize = source.itemSize;
        this.count = source.count;
        this.normalized = source.normalized;

        this.dynamic = source.dynamic;

        return this;

    },

    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;

    },

    copyArray: function ( array ) {

        this.array.set( array );

        return this;

    },

    copyColorsArray: function ( colors ) {

        var array = this.array, offset = 0;

        for ( var i = 0, l = colors.length; i < l; i ++ ) {

            var color = colors[ i ];

            if ( color === undefined ) {

                console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
                color = new Color();

            }

            array[ offset ++ ] = color.r;
            array[ offset ++ ] = color.g;
            array[ offset ++ ] = color.b;

        }

        return this;

    },

    copyIndicesArray: function ( indices ) {

        var array = this.array, offset = 0;

        for ( var i = 0, l = indices.length; i < l; i ++ ) {

            var index = indices[ i ];

            array[ offset ++ ] = index.a;
            array[ offset ++ ] = index.b;
            array[ offset ++ ] = index.c;

        }

        return this;

    },

    copyVector2sArray: function ( vectors ) {

        var array = this.array, offset = 0;

        for ( var i = 0, l = vectors.length; i < l; i ++ ) {

            var vector = vectors[ i ];

            if ( vector === undefined ) {

                console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
                vector = new Vector2();

            }

            array[ offset ++ ] = vector.x;
            array[ offset ++ ] = vector.y;

        }

        return this;

    },

    copyVector3sArray: function ( vectors ) {

        var array = this.array, offset = 0;

        for ( var i = 0, l = vectors.length; i < l; i ++ ) {

            var vector = vectors[ i ];

            if ( vector === undefined ) {

                console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
                vector = new Vector3();

            }

            array[ offset ++ ] = vector.x;
            array[ offset ++ ] = vector.y;
            array[ offset ++ ] = vector.z;

        }

        return this;

    },

    copyVector4sArray: function ( vectors ) {

        var array = this.array, offset = 0;

        for ( var i = 0, l = vectors.length; i < l; i ++ ) {

            var vector = vectors[ i ];

            if ( vector === undefined ) {

                console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
                vector = new Vector4();

            }

            array[ offset ++ ] = vector.x;
            array[ offset ++ ] = vector.y;
            array[ offset ++ ] = vector.z;
            array[ offset ++ ] = vector.w;

        }

        return this;

    },

    set: function ( value, offset ) {

        if ( offset === undefined ) offset = 0;

        this.array.set( value, offset );

        return this;

    },

    getX: function ( index ) {

        return this.array[ index * this.itemSize ];

    },

    setX: function ( index, x ) {

        this.array[ index * this.itemSize ] = x;

        return this;

    },

    getY: function ( index ) {

        return this.array[ index * this.itemSize + 1 ];

    },

    setY: function ( index, y ) {

        this.array[ index * this.itemSize + 1 ] = y;

        return this;

    },

    getZ: function ( index ) {

        return this.array[ index * this.itemSize + 2 ];

    },

    setZ: function ( index, z ) {

        this.array[ index * this.itemSize + 2 ] = z;

        return this;

    },

    getW: function ( index ) {

        return this.array[ index * this.itemSize + 3 ];

    },

    setW: function ( index, w ) {

        this.array[ index * this.itemSize + 3 ] = w;

        return this;

    },

    setXY: function ( index, x, y ) {

        index *= this.itemSize;

        this.array[ index + 0 ] = x;
        this.array[ index + 1 ] = y;

        return this;

    },

    setXYZ: function ( index, x, y, z ) {

        index *= this.itemSize;

        this.array[ index + 0 ] = 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 + 0 ] = x;
        this.array[ index + 1 ] = y;
        this.array[ index + 2 ] = z;
        this.array[ index + 3 ] = w;

        return this;

    },

    onUpload: function ( callback ) {

        this.onUploadCallback = callback;

        return this;

    },

    clone: function () {

        return new this.constructor( this.array, this.itemSize ).copy( this );

    }

} );

//

function Int8BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Int8Array( array ), itemSize );

}

Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;


function Uint8BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Uint8Array( array ), itemSize );

}

Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;


function Uint8ClampedBufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize );

}

Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;


function Int16BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Int16Array( array ), itemSize );

}

Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;


function Uint16BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Uint16Array( array ), itemSize );

}

Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;


function Int32BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Int32Array( array ), itemSize );

}

Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;


function Uint32BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Uint32Array( array ), itemSize );

}

Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;


function Float32BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Float32Array( array ), itemSize );

}

Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;


function Float64BufferAttribute( array, itemSize ) {

    BufferAttribute.call( this, new Float64Array( array ), itemSize );

}

Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;

/**
 * @author mrdoob / http://mrdoob.com/
 */

function DirectGeometry() {

    this.indices = [];
    this.vertices = [];
    this.normals = [];
    this.colors = [];
    this.uvs = [];
    this.uvs2 = [];

    this.groups = [];

    this.morphTargets = {};

    this.skinWeights = [];
    this.skinIndices = [];

    // this.lineDistances = [];

    this.boundingBox = null;
    this.boundingSphere = null;

    // update flags

    this.verticesNeedUpdate = false;
    this.normalsNeedUpdate = false;
    this.colorsNeedUpdate = false;
    this.uvsNeedUpdate = false;
    this.groupsNeedUpdate = false;

}

Object.assign( DirectGeometry.prototype, {

    computeGroups: function ( geometry ) {

        var group;
        var groups = [];
        var materialIndex = undefined;

        var faces = geometry.faces;

        for ( var i = 0; i < faces.length; i ++ ) {

            var face = faces[ i ];

            // materials

            if ( face.materialIndex !== materialIndex ) {

                materialIndex = face.materialIndex;

                if ( group !== undefined ) {

                    group.count = ( i * 3 ) - group.start;
                    groups.push( group );

                }

                group = {
                    start: i * 3,
                    materialIndex: materialIndex
                };

            }

        }

        if ( group !== undefined ) {

            group.count = ( i * 3 ) - group.start;
            groups.push( group );

        }

        this.groups = groups;

    },

    fromGeometry: function ( geometry ) {

        var faces = geometry.faces;
        var vertices = geometry.vertices;
        var faceVertexUvs = geometry.faceVertexUvs;

        var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
        var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;

        // morphs

        var morphTargets = geometry.morphTargets;
        var morphTargetsLength = morphTargets.length;

        var morphTargetsPosition;

        if ( morphTargetsLength > 0 ) {

            morphTargetsPosition = [];

            for ( var i = 0; i < morphTargetsLength; i ++ ) {

                morphTargetsPosition[ i ] = [];

            }

            this.morphTargets.position = morphTargetsPosition;

        }

        var morphNormals = geometry.morphNormals;
        var morphNormalsLength = morphNormals.length;

        var morphTargetsNormal;

        if ( morphNormalsLength > 0 ) {

            morphTargetsNormal = [];

            for ( var i = 0; i < morphNormalsLength; i ++ ) {

                morphTargetsNormal[ i ] = [];

            }

            this.morphTargets.normal = morphTargetsNormal;

        }

        // skins

        var skinIndices = geometry.skinIndices;
        var skinWeights = geometry.skinWeights;

        var hasSkinIndices = skinIndices.length === vertices.length;
        var hasSkinWeights = skinWeights.length === vertices.length;

        //

        for ( var i = 0; i < faces.length; i ++ ) {

            var face = faces[ i ];

            this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );

            var vertexNormals = face.vertexNormals;

            if ( vertexNormals.length === 3 ) {

                this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );

            } else {

                var normal = face.normal;

                this.normals.push( normal, normal, normal );

            }

            var vertexColors = face.vertexColors;

            if ( vertexColors.length === 3 ) {

                this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );

            } else {

                var color = face.color;

                this.colors.push( color, color, color );

            }

            if ( hasFaceVertexUv === true ) {

                var vertexUvs = faceVertexUvs[ 0 ][ i ];

                if ( vertexUvs !== undefined ) {

                    this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );

                } else {

                    console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );

                    this.uvs.push( new Vector2(), new Vector2(), new Vector2() );

                }

            }

            if ( hasFaceVertexUv2 === true ) {

                var vertexUvs = faceVertexUvs[ 1 ][ i ];

                if ( vertexUvs !== undefined ) {

                    this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );

                } else {

                    console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );

                    this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );

                }

            }

            // morphs

            for ( var j = 0; j < morphTargetsLength; j ++ ) {

                var morphTarget = morphTargets[ j ].vertices;

                morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );

            }

            for ( var j = 0; j < morphNormalsLength; j ++ ) {

                var morphNormal = morphNormals[ j ].vertexNormals[ i ];

                morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );

            }

            // skins

            if ( hasSkinIndices ) {

                this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );

            }

            if ( hasSkinWeights ) {

                this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );

            }

        }

        this.computeGroups( geometry );

        this.verticesNeedUpdate = geometry.verticesNeedUpdate;
        this.normalsNeedUpdate = geometry.normalsNeedUpdate;
        this.colorsNeedUpdate = geometry.colorsNeedUpdate;
        this.uvsNeedUpdate = geometry.uvsNeedUpdate;
        this.groupsNeedUpdate = geometry.groupsNeedUpdate;

        return this;

    }

} );

function arrayMax( array ) {

    if ( array.length === 0 ) return - Infinity;

    var max = array[ 0 ];

    for ( var i = 1, l = array.length; i < l; ++ i ) {

        if ( array[ i ] > max ) max = array[ i ];

    }

    return max;

}

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

function BufferGeometry() {

    Object.defineProperty( this, 'id', { value: GeometryIdCount() } );

    this.uuid = _Math.generateUUID();

    this.name = '';
    this.type = 'BufferGeometry';

    this.index = null;
    this.attributes = {};

    this.morphAttributes = {};

    this.groups = [];

    this.boundingBox = null;
    this.boundingSphere = null;

    this.drawRange = { start: 0, count: Infinity };

}

BufferGeometry.MaxIndex = 65535;

Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, {

    isBufferGeometry: true,

    getIndex: function () {

        return this.index;

    },

    setIndex: function ( index ) {

        if ( Array.isArray( index ) ) {

            this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );

        } else {

            this.index = index;

        }

    },

    addAttribute: function ( name, attribute ) {

        if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {

            console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );

            this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );

            return;

        }

        if ( name === 'index' ) {

            console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
            this.setIndex( attribute );

            return;

        }

        this.attributes[ name ] = attribute;

        return this;

    },

    getAttribute: function ( name ) {

        return this.attributes[ name ];

    },

    removeAttribute: function ( name ) {

        delete this.attributes[ name ];

        return this;

    },

    addGroup: function ( start, count, materialIndex ) {

        this.groups.push( {

            start: start,
            count: count,
            materialIndex: materialIndex !== undefined ? materialIndex : 0

        } );

    },

    clearGroups: function () {

        this.groups = [];

    },

    setDrawRange: function ( start, count ) {

        this.drawRange.start = start;
        this.drawRange.count = count;

    },

    applyMatrix: function ( matrix ) {

        var position = this.attributes.position;

        if ( position !== undefined ) {

            matrix.applyToBufferAttribute( position );
            position.needsUpdate = true;

        }

        var normal = this.attributes.normal;

        if ( normal !== undefined ) {

            var normalMatrix = new Matrix3().getNormalMatrix( matrix );

            normalMatrix.applyToBufferAttribute( normal );
            normal.needsUpdate = true;

        }

        if ( this.boundingBox !== null ) {

            this.computeBoundingBox();

        }

        if ( this.boundingSphere !== null ) {

            this.computeBoundingSphere();

        }

        return this;

    },

    rotateX: function () {

        // rotate geometry around world x-axis

        var m1 = new Matrix4();

        return function rotateX( angle ) {

            m1.makeRotationX( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    rotateY: function () {

        // rotate geometry around world y-axis

        var m1 = new Matrix4();

        return function rotateY( angle ) {

            m1.makeRotationY( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    rotateZ: function () {

        // rotate geometry around world z-axis

        var m1 = new Matrix4();

        return function rotateZ( angle ) {

            m1.makeRotationZ( angle );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    translate: function () {

        // translate geometry

        var m1 = new Matrix4();

        return function translate( x, y, z ) {

            m1.makeTranslation( x, y, z );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    scale: function () {

        // scale geometry

        var m1 = new Matrix4();

        return function scale( x, y, z ) {

            m1.makeScale( x, y, z );

            this.applyMatrix( m1 );

            return this;

        };

    }(),

    lookAt: function () {

        var obj = new Object3D();

        return function lookAt( vector ) {

            obj.lookAt( vector );

            obj.updateMatrix();

            this.applyMatrix( obj.matrix );

        };

    }(),

    center: function () {

        this.computeBoundingBox();

        var offset = this.boundingBox.getCenter().negate();

        this.translate( offset.x, offset.y, offset.z );

        return offset;

    },

    setFromObject: function ( object ) {

        // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );

        var geometry = object.geometry;

        if ( object.isPoints || object.isLine ) {

            var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
            var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );

            this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
            this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );

            if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {

                var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );

                this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );

            }

            if ( geometry.boundingSphere !== null ) {

                this.boundingSphere = geometry.boundingSphere.clone();

            }

            if ( geometry.boundingBox !== null ) {

                this.boundingBox = geometry.boundingBox.clone();

            }

        } else if ( object.isMesh ) {

            if ( geometry && geometry.isGeometry ) {

                this.fromGeometry( geometry );

            }

        }

        return this;

    },

    updateFromObject: function ( object ) {

        var geometry = object.geometry;

        if ( object.isMesh ) {

            var direct = geometry.__directGeometry;

            if ( geometry.elementsNeedUpdate === true ) {

                direct = undefined;
                geometry.elementsNeedUpdate = false;

            }

            if ( direct === undefined ) {

                return this.fromGeometry( geometry );

            }

            direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
            direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
            direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
            direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
            direct.groupsNeedUpdate = geometry.groupsNeedUpdate;

            geometry.verticesNeedUpdate = false;
            geometry.normalsNeedUpdate = false;
            geometry.colorsNeedUpdate = false;
            geometry.uvsNeedUpdate = false;
            geometry.groupsNeedUpdate = false;

            geometry = direct;

        }

        var attribute;

        if ( geometry.verticesNeedUpdate === true ) {

            attribute = this.attributes.position;

            if ( attribute !== undefined ) {

                attribute.copyVector3sArray( geometry.vertices );
                attribute.needsUpdate = true;

            }

            geometry.verticesNeedUpdate = false;

        }

        if ( geometry.normalsNeedUpdate === true ) {

            attribute = this.attributes.normal;

            if ( attribute !== undefined ) {

                attribute.copyVector3sArray( geometry.normals );
                attribute.needsUpdate = true;

            }

            geometry.normalsNeedUpdate = false;

        }

        if ( geometry.colorsNeedUpdate === true ) {

            attribute = this.attributes.color;

            if ( attribute !== undefined ) {

                attribute.copyColorsArray( geometry.colors );
                attribute.needsUpdate = true;

            }

            geometry.colorsNeedUpdate = false;

        }

        if ( geometry.uvsNeedUpdate ) {

            attribute = this.attributes.uv;

            if ( attribute !== undefined ) {

                attribute.copyVector2sArray( geometry.uvs );
                attribute.needsUpdate = true;

            }

            geometry.uvsNeedUpdate = false;

        }

        if ( geometry.lineDistancesNeedUpdate ) {

            attribute = this.attributes.lineDistance;

            if ( attribute !== undefined ) {

                attribute.copyArray( geometry.lineDistances );
                attribute.needsUpdate = true;

            }

            geometry.lineDistancesNeedUpdate = false;

        }

        if ( geometry.groupsNeedUpdate ) {

            geometry.computeGroups( object.geometry );
            this.groups = geometry.groups;

            geometry.groupsNeedUpdate = false;

        }

        return this;

    },

    fromGeometry: function ( geometry ) {

        geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );

        return this.fromDirectGeometry( geometry.__directGeometry );

    },

    fromDirectGeometry: function ( geometry ) {

        var positions = new Float32Array( geometry.vertices.length * 3 );
        this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );

        if ( geometry.normals.length > 0 ) {

            var normals = new Float32Array( geometry.normals.length * 3 );
            this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );

        }

        if ( geometry.colors.length > 0 ) {

            var colors = new Float32Array( geometry.colors.length * 3 );
            this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );

        }

        if ( geometry.uvs.length > 0 ) {

            var uvs = new Float32Array( geometry.uvs.length * 2 );
            this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );

        }

        if ( geometry.uvs2.length > 0 ) {

            var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
            this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );

        }

        if ( geometry.indices.length > 0 ) {

            var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;
            var indices = new TypeArray( geometry.indices.length * 3 );
            this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );

        }

        // groups

        this.groups = geometry.groups;

        // morphs

        for ( var name in geometry.morphTargets ) {

            var array = [];
            var morphTargets = geometry.morphTargets[ name ];

            for ( var i = 0, l = morphTargets.length; i < l; i ++ ) {

                var morphTarget = morphTargets[ i ];

                var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );

                array.push( attribute.copyVector3sArray( morphTarget ) );

            }

            this.morphAttributes[ name ] = array;

        }

        // skinning

        if ( geometry.skinIndices.length > 0 ) {

            var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
            this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );

        }

        if ( geometry.skinWeights.length > 0 ) {

            var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
            this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );

        }

        //

        if ( geometry.boundingSphere !== null ) {

            this.boundingSphere = geometry.boundingSphere.clone();

        }

        if ( geometry.boundingBox !== null ) {

            this.boundingBox = geometry.boundingBox.clone();

        }

        return this;

    },

    computeBoundingBox: function () {

        if ( this.boundingBox === null ) {

            this.boundingBox = new Box3();

        }

        var position = this.attributes.position;

        if ( position !== undefined ) {

            this.boundingBox.setFromBufferAttribute( position );

        } else {

            this.boundingBox.makeEmpty();

        }

        if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {

            console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );

        }

    },

    computeBoundingSphere: function () {

        var box = new Box3();
        var vector = new Vector3();

        return function computeBoundingSphere() {

            if ( this.boundingSphere === null ) {

                this.boundingSphere = new Sphere();

            }

            var position = this.attributes.position;

            if ( position ) {

                var center = this.boundingSphere.center;

                box.setFromBufferAttribute( position );
                box.getCenter( 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 = position.count; i < il; i ++ ) {

                    vector.x = position.getX( i );
                    vector.y = position.getY( i );
                    vector.z = position.getZ( i );
                    maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );

                }

                this.boundingSphere.radius = Math.sqrt( maxRadiusSq );

                if ( isNaN( this.boundingSphere.radius ) ) {

                    console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );

                }

            }

        };

    }(),

    computeFaceNormals: function () {

        // backwards compatibility

    },

    computeVertexNormals: function () {

        var index = this.index;
        var attributes = this.attributes;
        var groups = this.groups;

        if ( attributes.position ) {

            var positions = attributes.position.array;

            if ( attributes.normal === undefined ) {

                this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );

            } else {

                // reset existing normals to zero

                var array = attributes.normal.array;

                for ( var i = 0, il = array.length; i < il; i ++ ) {

                    array[ i ] = 0;

                }

            }

            var normals = attributes.normal.array;

            var vA, vB, vC;
            var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
            var cb = new Vector3(), ab = new Vector3();

            // indexed elements

            if ( index ) {

                var indices = index.array;

                if ( groups.length === 0 ) {

                    this.addGroup( 0, indices.length );

                }

                for ( var j = 0, jl = groups.length; j < jl; ++ j ) {

                    var group = groups[ j ];

                    var start = group.start;
                    var count = group.count;

                    for ( var i = start, il = start + count; i < il; i += 3 ) {

                        vA = indices[ i + 0 ] * 3;
                        vB = indices[ i + 1 ] * 3;
                        vC = 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;

        }

    },

    merge: function ( geometry, offset ) {

        if ( ! ( geometry && geometry.isBufferGeometry ) ) {

            console.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;

        var x, y, z, n;

        for ( var i = 0, il = normals.count; i < il; i ++ ) {

            x = normals.getX( i );
            y = normals.getY( i );
            z = normals.getZ( i );

            n = 1.0 / Math.sqrt( x * x + y * y + z * z );

            normals.setXYZ( i, x * n, y * n, z * n );

        }

    },

    toNonIndexed: function () {

        if ( this.index === null ) {

            console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
            return this;

        }

        var geometry2 = new BufferGeometry();

        var indices = this.index.array;
        var attributes = this.attributes;

        for ( var name in attributes ) {

            var attribute = attributes[ name ];

            var array = attribute.array;
            var itemSize = attribute.itemSize;

            var array2 = new array.constructor( indices.length * itemSize );

            var index = 0, index2 = 0;

            for ( var i = 0, l = indices.length; i < l; i ++ ) {

                index = indices[ i ] * itemSize;

                for ( var j = 0; j < itemSize; j ++ ) {

                    array2[ index2 ++ ] = array[ index ++ ];

                }

            }

            geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );

        }

        return geometry2;

    },

    toJSON: function () {

        var data = {
            metadata: {
                version: 4.5,
                type: 'BufferGeometry',
                generator: 'BufferGeometry.toJSON'
            }
        };

        // standard BufferGeometry serialization

        data.uuid = this.uuid;
        data.type = this.type;
        if ( this.name !== '' ) data.name = this.name;

        if ( this.parameters !== undefined ) {

            var parameters = this.parameters;

            for ( var key in parameters ) {

                if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];

            }

            return data;

        }

        data.data = { attributes: {} };

        var index = this.index;

        if ( index !== null ) {

            var array = Array.prototype.slice.call( index.array );

            data.data.index = {
                type: index.array.constructor.name,
                array: array
            };

        }

        var attributes = this.attributes;

        for ( var key in attributes ) {

            var attribute = attributes[ key ];

            var array = Array.prototype.slice.call( attribute.array );

            data.data.attributes[ key ] = {
                itemSize: attribute.itemSize,
                type: attribute.array.constructor.name,
                array: array,
                normalized: attribute.normalized
            };

        }

        var groups = this.groups;

        if ( groups.length > 0 ) {

            data.data.groups = JSON.parse( JSON.stringify( groups ) );

        }

        var boundingSphere = this.boundingSphere;

        if ( boundingSphere !== null ) {

            data.data.boundingSphere = {
                center: boundingSphere.center.toArray(),
                radius: boundingSphere.radius
            };

        }

        return data;

    },

    clone: function () {

        /*
         // Handle primitives

         var parameters = this.parameters;

         if ( parameters !== undefined ) {

         var values = [];

         for ( var key in parameters ) {

         values.push( parameters[ key ] );

         }

         var geometry = Object.create( this.constructor.prototype );
         this.constructor.apply( geometry, values );
         return geometry;

         }

         return new this.constructor().copy( this );
         */

        return new BufferGeometry().copy( this );

    },

    copy: function ( source ) {

        var name, i, l;

        // reset

        this.index = null;
        this.attributes = {};
        this.morphAttributes = {};
        this.groups = [];
        this.boundingBox = null;
        this.boundingSphere = null;

        // name

        this.name = source.name;

        // index

        var index = source.index;

        if ( index !== null ) {

            this.setIndex( index.clone() );

        }

        // attributes

        var attributes = source.attributes;

        for ( name in attributes ) {

            var attribute = attributes[ name ];
            this.addAttribute( name, attribute.clone() );

        }

        // morph attributes

        var morphAttributes = source.morphAttributes;

        for ( name in morphAttributes ) {

            var array = [];
            var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes

            for ( i = 0, l = morphAttribute.length; i < l; i ++ ) {

                array.push( morphAttribute[ i ].clone() );

            }

            this.morphAttributes[ name ] = array;

        }

        // groups

        var groups = source.groups;

        for ( i = 0, l = groups.length; i < l; i ++ ) {

            var group = groups[ i ];
            this.addGroup( group.start, group.count, group.materialIndex );

        }

        // bounding box

        var boundingBox = source.boundingBox;

        if ( boundingBox !== null ) {

            this.boundingBox = boundingBox.clone();

        }

        // bounding sphere

        var boundingSphere = source.boundingSphere;

        if ( boundingSphere !== null ) {

            this.boundingSphere = boundingSphere.clone();

        }

        // draw range

        this.drawRange.start = source.drawRange.start;
        this.drawRange.count = source.drawRange.count;

        return this;

    },

    dispose: function () {

        this.dispatchEvent( { type: 'dispose' } );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

// BoxGeometry

function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {

    Geometry.call( this );

    this.type = 'BoxGeometry';

    this.parameters = {
        width: width,
        height: height,
        depth: depth,
        widthSegments: widthSegments,
        heightSegments: heightSegments,
        depthSegments: depthSegments
    };

    this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
    this.mergeVertices();

}

BoxGeometry.prototype = Object.create( Geometry.prototype );
BoxGeometry.prototype.constructor = BoxGeometry;

// BoxBufferGeometry

function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {

    BufferGeometry.call( this );

    this.type = 'BoxBufferGeometry';

    this.parameters = {
        width: width,
        height: height,
        depth: depth,
        widthSegments: widthSegments,
        heightSegments: heightSegments,
        depthSegments: depthSegments
    };

    var scope = this;

    // segments

    widthSegments = Math.floor( widthSegments ) || 1;
    heightSegments = Math.floor( heightSegments ) || 1;
    depthSegments = Math.floor( depthSegments ) || 1;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var numberOfVertices = 0;
    var groupStart = 0;

    // build each side of the box geometry

    buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height,   width,  depthSegments, heightSegments, 0 ); // px
    buildPlane( 'z', 'y', 'x',   1, - 1, depth, height, - width,  depthSegments, heightSegments, 1 ); // nx
    buildPlane( 'x', 'z', 'y',   1,   1, width, depth,    height, widthSegments, depthSegments,  2 ); // py
    buildPlane( 'x', 'z', 'y',   1, - 1, width, depth,  - height, widthSegments, depthSegments,  3 ); // ny
    buildPlane( 'x', 'y', 'z',   1, - 1, width, height,   depth,  widthSegments, heightSegments, 4 ); // pz
    buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth,  widthSegments, heightSegments, 5 ); // nz

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {

        var segmentWidth = width / gridX;
        var segmentHeight = height / gridY;

        var widthHalf = width / 2;
        var heightHalf = height / 2;
        var depthHalf = depth / 2;

        var gridX1 = gridX + 1;
        var gridY1 = gridY + 1;

        var vertexCounter = 0;
        var groupCount = 0;

        var ix, iy;

        var vector = new Vector3();

        // generate vertices, normals and uvs

        for ( iy = 0; iy < gridY1; iy ++ ) {

            var y = iy * segmentHeight - heightHalf;

            for ( ix = 0; ix < gridX1; ix ++ ) {

                var x = ix * segmentWidth - widthHalf;

                // set values to correct vector component

                vector[ u ] = x * udir;
                vector[ v ] = y * vdir;
                vector[ w ] = depthHalf;

                // now apply vector to vertex buffer

                vertices.push( vector.x, vector.y, vector.z );

                // set values to correct vector component

                vector[ u ] = 0;
                vector[ v ] = 0;
                vector[ w ] = depth > 0 ? 1 : - 1;

                // now apply vector to normal buffer

                normals.push( vector.x, vector.y, vector.z );

                // uvs

                uvs.push( ix / gridX );
                uvs.push( 1 - ( iy / gridY ) );

                // counters

                vertexCounter += 1;

            }

        }

        // indices

        // 1. you need three indices to draw a single face
        // 2. a single segment consists of two faces
        // 3. so we need to generate six (2*3) indices per segment

        for ( iy = 0; iy < gridY; iy ++ ) {

            for ( ix = 0; ix < gridX; ix ++ ) {

                var a = numberOfVertices + ix + gridX1 * iy;
                var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
                var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
                var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;

                // faces

                indices.push( a, b, d );
                indices.push( b, c, d );

                // increase counter

                groupCount += 6;

            }

        }

        // add a group to the geometry. this will ensure multi material support

        scope.addGroup( groupStart, groupCount, materialIndex );

        // calculate new start value for groups

        groupStart += groupCount;

        // update total number of vertices

        numberOfVertices += vertexCounter;

    }

}

BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

// PlaneGeometry

function PlaneGeometry( width, height, widthSegments, heightSegments ) {

    Geometry.call( this );

    this.type = 'PlaneGeometry';

    this.parameters = {
        width: width,
        height: height,
        widthSegments: widthSegments,
        heightSegments: heightSegments
    };

    this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
    this.mergeVertices();

}

PlaneGeometry.prototype = Object.create( Geometry.prototype );
PlaneGeometry.prototype.constructor = PlaneGeometry;

// PlaneBufferGeometry

function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {

    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 = Math.floor( widthSegments ) || 1;
    var gridY = Math.floor( heightSegments ) || 1;

    var gridX1 = gridX + 1;
    var gridY1 = gridY + 1;

    var segment_width = width / gridX;
    var segment_height = height / gridY;

    var ix, iy;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // generate vertices, normals and uvs

    for ( iy = 0; iy < gridY1; iy ++ ) {

        var y = iy * segment_height - height_half;

        for ( ix = 0; ix < gridX1; ix ++ ) {

            var x = ix * segment_width - width_half;

            vertices.push( x, - y, 0 );

            normals.push( 0, 0, 1 );

            uvs.push( ix / gridX );
            uvs.push( 1 - ( iy / gridY ) );

        }

    }

    // indices

    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;

            // faces

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;

/**
 * @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> ),
 *  lightMapIntensity: <float>
 *
 *  aoMap: new THREE.Texture( <Image> ),
 *  aoMapIntensity: <float>
 *
 *  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,
 *  depthTest: <bool>,
 *  depthWrite: <bool>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>
 * }
 */

function MeshBasicMaterial( parameters ) {

    Material.call( this );

    this.type = 'MeshBasicMaterial';

    this.color = new Color( 0xffffff ); // emissive

    this.map = null;

    this.lightMap = null;
    this.lightMapIntensity = 1.0;

    this.aoMap = null;
    this.aoMapIntensity = 1.0;

    this.specularMap = null;

    this.alphaMap = null;

    this.envMap = null;
    this.combine = MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.skinning = false;
    this.morphTargets = false;

    this.lights = false;

    this.setValues( parameters );

}

MeshBasicMaterial.prototype = Object.create( Material.prototype );
MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;

MeshBasicMaterial.prototype.isMeshBasicMaterial = true;

MeshBasicMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );

    this.map = source.map;

    this.lightMap = source.lightMap;
    this.lightMapIntensity = source.lightMapIntensity;

    this.aoMap = source.aoMap;
    this.aoMapIntensity = source.aoMapIntensity;

    this.specularMap = source.specularMap;

    this.alphaMap = source.alphaMap;

    this.envMap = source.envMap;
    this.combine = source.combine;
    this.reflectivity = source.reflectivity;
    this.refractionRatio = source.refractionRatio;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;
    this.wireframeLinecap = source.wireframeLinecap;
    this.wireframeLinejoin = source.wireframeLinejoin;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;

    return this;

};

/**
 * @author bhouston / http://clara.io
 */

function Ray( origin, direction ) {

    this.origin = ( origin !== undefined ) ? origin : new Vector3();
    this.direction = ( direction !== undefined ) ? direction : new Vector3();

}

Object.assign( Ray.prototype, {

    set: function ( origin, direction ) {

        this.origin.copy( origin );
        this.direction.copy( direction );

        return this;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( ray ) {

        this.origin.copy( ray.origin );
        this.direction.copy( ray.direction );

        return this;

    },

    at: function ( t, optionalTarget ) {

        var result = optionalTarget || new Vector3();

        return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );

    },

    lookAt: function ( v ) {

        this.direction.copy( v ).sub( this.origin ).normalize();

        return this;

    },

    recast: function () {

        var v1 = new Vector3();

        return function recast( t ) {

            this.origin.copy( this.at( t, v1 ) );

            return this;

        };

    }(),

    closestPointToPoint: function ( point, optionalTarget ) {

        var result = optionalTarget || new 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 ( point ) {

        return Math.sqrt( this.distanceSqToPoint( point ) );

    },

    distanceSqToPoint: function () {

        var v1 = new Vector3();

        return function distanceSqToPoint( point ) {

            var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );

            // point behind the ray

            if ( directionDistance < 0 ) {

                return this.origin.distanceToSquared( point );

            }

            v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );

            return v1.distanceToSquared( point );

        };

    }(),

    distanceSqToSegment: function () {

        var segCenter = new Vector3();
        var segDir = new Vector3();
        var diff = new Vector3();

        return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

            // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
            // 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;

        };

    }(),

    intersectSphere: function () {

        var v1 = new Vector3();

        return function intersectSphere( 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 );

        };

    }(),

    intersectsSphere: function ( sphere ) {

        return this.distanceToPoint( sphere.center ) <= sphere.radius;

    },

    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 );

    },

    intersectsPlane: 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;

    },

    intersectBox: function ( box, optionalTarget ) {

        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 );

    },

    intersectsBox: ( function () {

        var v = new Vector3();

        return function intersectsBox( box ) {

            return this.intersectBox( box, v ) !== null;

        };

    } )(),

    intersectTriangle: function () {

        // Compute the offset origin, edges, and normal.
        var diff = new Vector3();
        var edge1 = new Vector3();
        var edge2 = new Vector3();
        var normal = new Vector3();

        return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {

            // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h

            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.origin.applyMatrix4( matrix4 );
        this.direction.transformDirection( matrix4 );

        return this;

    },

    equals: function ( ray ) {

        return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

    }

} );

/**
 * @author bhouston / http://clara.io
 */

function Line3( start, end ) {

    this.start = ( start !== undefined ) ? start : new Vector3();
    this.end = ( end !== undefined ) ? end : new Vector3();

}

Object.assign( Line3.prototype, {

    set: function ( start, end ) {

        this.start.copy( start );
        this.end.copy( end );

        return this;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( line ) {

        this.start.copy( line.start );
        this.end.copy( line.end );

        return this;

    },

    getCenter: function ( optionalTarget ) {

        var result = optionalTarget || new Vector3();
        return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );

    },

    delta: function ( optionalTarget ) {

        var result = optionalTarget || new 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 Vector3();

        return this.delta( result ).multiplyScalar( t ).add( this.start );

    },

    closestPointToPointParameter: function () {

        var startP = new Vector3();
        var startEnd = new Vector3();

        return function closestPointToPointParameter( 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 = _Math.clamp( t, 0, 1 );

            }

            return t;

        };

    }(),

    closestPointToPoint: function ( point, clampToLine, optionalTarget ) {

        var t = this.closestPointToPointParameter( point, clampToLine );

        var result = optionalTarget || new 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 );

    }

} );

/**
 * @author bhouston / http://clara.io
 * @author mrdoob / http://mrdoob.com/
 */

function Triangle( a, b, c ) {

    this.a = ( a !== undefined ) ? a : new Vector3();
    this.b = ( b !== undefined ) ? b : new Vector3();
    this.c = ( c !== undefined ) ? c : new Vector3();

}

Object.assign( Triangle, {

    normal: function () {

        var v0 = new Vector3();

        return function normal( a, b, c, optionalTarget ) {

            var result = optionalTarget || new 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 barycentric coordinates
    // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
    barycoordFromPoint: function () {

        var v0 = new Vector3();
        var v1 = new Vector3();
        var v2 = new Vector3();

        return function barycoordFromPoint( 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 Vector3();

            // collinear 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;

            // barycentric coordinates must always sum to 1
            return result.set( 1 - u - v, v, u );

        };

    }(),

    containsPoint: function () {

        var v1 = new Vector3();

        return function containsPoint( point, a, b, c ) {

            var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );

            return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );

        };

    }()

} );

Object.assign( Triangle.prototype, {

    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;

    },

    clone: function () {

        return new this.constructor().copy( 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 Vector3();
        var v1 = new Vector3();

        return function area() {

            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 Vector3();
        return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );

    },

    normal: function ( optionalTarget ) {

        return Triangle.normal( this.a, this.b, this.c, optionalTarget );

    },

    plane: function ( optionalTarget ) {

        var result = optionalTarget || new Plane();

        return result.setFromCoplanarPoints( this.a, this.b, this.c );

    },

    barycoordFromPoint: function ( point, optionalTarget ) {

        return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );

    },

    containsPoint: function ( point ) {

        return Triangle.containsPoint( point, this.a, this.b, this.c );

    },

    closestPointToPoint: function () {

        var plane = new Plane();
        var edgeList = [ new Line3(), new Line3(), new Line3() ];
        var projectedPoint = new Vector3();
        var closestPoint = new Vector3();

        return function closestPointToPoint( point, optionalTarget ) {

            var result = optionalTarget || new Vector3();
            var minDistance = Infinity;

            // project the point onto the plane of the triangle

            plane.setFromCoplanarPoints( this.a, this.b, this.c );
            plane.projectPoint( point, projectedPoint );

            // check if the projection lies within the triangle

            if( this.containsPoint( projectedPoint ) === true ) {

                // if so, this is the closest point

                result.copy( projectedPoint );

            } else {

                // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices

                edgeList[ 0 ].set( this.a, this.b );
                edgeList[ 1 ].set( this.b, this.c );
                edgeList[ 2 ].set( this.c, this.a );

                for( var i = 0; i < edgeList.length; i ++ ) {

                    edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );

                    var distance = projectedPoint.distanceToSquared( closestPoint );

                    if( distance < minDistance ) {

                        minDistance = distance;

                        result.copy( closestPoint );

                    }

                }

            }

            return result;

        };

    }(),

    equals: function ( triangle ) {

        return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 * @author jonobr1 / http://jonobr1.com/
 */

function Mesh( geometry, material ) {

    Object3D.call( this );

    this.type = 'Mesh';

    this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
    this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );

    this.drawMode = TrianglesDrawMode;

    this.updateMorphTargets();

}

Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Mesh,

    isMesh: true,

    setDrawMode: function ( value ) {

        this.drawMode = value;

    },

    copy: function ( source ) {

        Object3D.prototype.copy.call( this, source );

        this.drawMode = source.drawMode;

        return this;

    },

    updateMorphTargets: function () {

        var geometry = this.geometry;
        var m, ml, name;

        if ( geometry.isBufferGeometry ) {

            var morphAttributes = geometry.morphAttributes;
            var keys = Object.keys( morphAttributes );

            if ( keys.length > 0 ) {

                var morphAttribute = morphAttributes[ keys[ 0 ] ];

                if ( morphAttribute !== undefined ) {

                    this.morphTargetInfluences = [];
                    this.morphTargetDictionary = {};

                    for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) {

                        name = morphAttribute[ m ].name || String( m );

                        this.morphTargetInfluences.push( 0 );
                        this.morphTargetDictionary[ name ] = m;

                    }

                }

            }

        } else {

            var morphTargets = geometry.morphTargets;

            if ( morphTargets !== undefined && morphTargets.length > 0 ) {

                this.morphTargetInfluences = [];
                this.morphTargetDictionary = {};

                for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) {

                    name = morphTargets[ m ].name || String( m );

                    this.morphTargetInfluences.push( 0 );
                    this.morphTargetDictionary[ name ] = m;

                }

            }

        }

    },

    raycast: ( function () {

        var inverseMatrix = new Matrix4();
        var ray = new Ray();
        var sphere = new Sphere();

        var vA = new Vector3();
        var vB = new Vector3();
        var vC = new Vector3();

        var tempA = new Vector3();
        var tempB = new Vector3();
        var tempC = new Vector3();

        var uvA = new Vector2();
        var uvB = new Vector2();
        var uvC = new Vector2();

        var barycoord = new Vector3();

        var intersectionPoint = new Vector3();
        var intersectionPointWorld = new Vector3();

        function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {

            Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord );

            uv1.multiplyScalar( barycoord.x );
            uv2.multiplyScalar( barycoord.y );
            uv3.multiplyScalar( barycoord.z );

            uv1.add( uv2 ).add( uv3 );

            return uv1.clone();

        }

        function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {

            var intersect;
            var material = object.material;

            if ( material.side === BackSide ) {

                intersect = ray.intersectTriangle( pC, pB, pA, true, point );

            } else {

                intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );

            }

            if ( intersect === null ) return null;

            intersectionPointWorld.copy( point );
            intersectionPointWorld.applyMatrix4( object.matrixWorld );

            var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );

            if ( distance < raycaster.near || distance > raycaster.far ) return null;

            return {
                distance: distance,
                point: intersectionPointWorld.clone(),
                object: object
            };

        }

        function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {

            vA.fromBufferAttribute( position, a );
            vB.fromBufferAttribute( position, b );
            vC.fromBufferAttribute( position, c );

            var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint );

            if ( intersection ) {

                if ( uv ) {

                    uvA.fromBufferAttribute( uv, a );
                    uvB.fromBufferAttribute( uv, b );
                    uvC.fromBufferAttribute( uv, c );

                    intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );

                }

                intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );
                intersection.faceIndex = a;

            }

            return intersection;

        }

        return function raycast( raycaster, intersects ) {

            var geometry = this.geometry;
            var material = this.material;
            var matrixWorld = this.matrixWorld;

            if ( material === undefined ) return;

            // Checking boundingSphere distance to ray

            if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

            sphere.copy( geometry.boundingSphere );
            sphere.applyMatrix4( matrixWorld );

            if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;

            //

            inverseMatrix.getInverse( matrixWorld );
            ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

            // Check boundingBox before continuing

            if ( geometry.boundingBox !== null ) {

                if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;

            }

            var intersection;

            if ( geometry.isBufferGeometry ) {

                var a, b, c;
                var index = geometry.index;
                var position = geometry.attributes.position;
                var uv = geometry.attributes.uv;
                var i, l;

                if ( index !== null ) {

                    // indexed buffer geometry

                    for ( i = 0, l = index.count; i < l; i += 3 ) {

                        a = index.getX( i );
                        b = index.getX( i + 1 );
                        c = index.getX( i + 2 );

                        intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );

                        if ( intersection ) {

                            intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics
                            intersects.push( intersection );

                        }

                    }

                } else {

                    // non-indexed buffer geometry

                    for ( i = 0, l = position.count; i < l; i += 3 ) {

                        a = i;
                        b = i + 1;
                        c = i + 2;

                        intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );

                        if ( intersection ) {

                            intersection.index = a; // triangle number in positions buffer semantics
                            intersects.push( intersection );

                        }

                    }

                }

            } else if ( geometry.isGeometry ) {

                var fvA, fvB, fvC;
                var isMultiMaterial = Array.isArray( material );

                var vertices = geometry.vertices;
                var faces = geometry.faces;
                var uvs;

                var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
                if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;

                for ( var f = 0, fl = faces.length; f < fl; f ++ ) {

                    var face = faces[ f ];
                    var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;

                    if ( faceMaterial === undefined ) continue;

                    fvA = vertices[ face.a ];
                    fvB = vertices[ face.b ];
                    fvC = vertices[ face.c ];

                    if ( faceMaterial.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.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );
                            vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );
                            vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );

                        }

                        vA.add( fvA );
                        vB.add( fvB );
                        vC.add( fvC );

                        fvA = vA;
                        fvB = vB;
                        fvC = vC;

                    }

                    intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint );

                    if ( intersection ) {

                        if ( uvs && uvs[ f ] ) {

                            var uvs_f = uvs[ f ];
                            uvA.copy( uvs_f[ 0 ] );
                            uvB.copy( uvs_f[ 1 ] );
                            uvC.copy( uvs_f[ 2 ] );

                            intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );

                        }

                        intersection.face = face;
                        intersection.faceIndex = f;
                        intersects.push( intersection );

                    }

                }

            }

        };

    }() ),

    clone: function () {

        return new this.constructor( this.geometry, this.material ).copy( this );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLBackground( renderer, state, objects, premultipliedAlpha ) {

    var clearColor = new Color( 0x000000 );
    var clearAlpha = 0;

    var planeCamera, planeMesh;
    var boxCamera, boxMesh;

    function render( scene, camera, forceClear ) {

        var background = scene.background;

        if ( background === null ) {

            setClear( clearColor, clearAlpha );

        } else if ( background && background.isColor ) {

            setClear( background, 1 );
            forceClear = true;

        }

        if ( renderer.autoClear || forceClear ) {

            renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );

        }

        if ( background && background.isCubeTexture ) {

            if ( boxCamera === undefined ) {

                boxCamera = new PerspectiveCamera();

                boxMesh = new Mesh(
                    new BoxBufferGeometry( 5, 5, 5 ),
                    new ShaderMaterial( {
                        uniforms: ShaderLib.cube.uniforms,
                        vertexShader: ShaderLib.cube.vertexShader,
                        fragmentShader: ShaderLib.cube.fragmentShader,
                        side: BackSide,
                        depthTest: false,
                        depthWrite: false,
                        fog: false
                    } )
                );

            }

            boxCamera.projectionMatrix.copy( camera.projectionMatrix );

            boxCamera.matrixWorld.extractRotation( camera.matrixWorld );
            boxCamera.matrixWorldInverse.getInverse( boxCamera.matrixWorld );

            boxMesh.material.uniforms[ "tCube" ].value = background;
            boxMesh.modelViewMatrix.multiplyMatrices( boxCamera.matrixWorldInverse, boxMesh.matrixWorld );

            objects.update( boxMesh );

            renderer.renderBufferDirect( boxCamera, null, boxMesh.geometry, boxMesh.material, boxMesh, null );

        } else if ( background && background.isTexture ) {

            if ( planeCamera === undefined ) {

                planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

                planeMesh = new Mesh(
                    new PlaneBufferGeometry( 2, 2 ),
                    new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
                );

            }

            planeMesh.material.map = background;

            objects.update( planeMesh );

            renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null );

        }

    }

    function setClear( color, alpha ) {

        state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );

    }

    return {

        getClearColor: function () {

            return clearColor;

        },
        setClearColor: function ( color, alpha ) {

            clearColor.set( color );
            clearAlpha = alpha !== undefined ? alpha : 1;
            setClear( clearColor, clearAlpha );

        },
        getClearAlpha: function () {

            return clearAlpha;

        },
        setClearAlpha: function ( alpha ) {

            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        },
        render: render

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function painterSortStable( a, b ) {

    if ( a.renderOrder !== b.renderOrder ) {

        return a.renderOrder - b.renderOrder;

    } else if ( a.program && b.program && a.program !== b.program ) {

        return a.program.id - b.program.id;

    } 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.renderOrder !== b.renderOrder ) {

        return a.renderOrder - b.renderOrder;

    } if ( a.z !== b.z ) {

        return b.z - a.z;

    } else {

        return a.id - b.id;

    }

}

function WebGLRenderList() {

    var opaque = [];
    var opaqueLastIndex = - 1;

    var transparent = [];
    var transparentLastIndex = - 1;

    function init() {

        opaqueLastIndex = - 1;
        transparentLastIndex = - 1;

    }

    function push( object, geometry, material, z, group ) {

        var array, index;

        // allocate the next position in the appropriate array

        if ( material.transparent ) {

            array = transparent;
            index = ++ transparentLastIndex;

        } else {

            array = opaque;
            index = ++ opaqueLastIndex;

        }

        // recycle existing render item or grow the array

        var renderItem = array[ index ];

        if ( renderItem ) {

            renderItem.id = object.id;
            renderItem.object = object;
            renderItem.geometry = geometry;
            renderItem.material = material;
            renderItem.program = material.program;
            renderItem.renderOrder = object.renderOrder;
            renderItem.z = z;
            renderItem.group = group;

        } else {

            renderItem = {
                id: object.id,
                object: object,
                geometry: geometry,
                material: material,
                program: material.program,
                renderOrder: object.renderOrder,
                z: z,
                group: group
            };

            // assert( index === array.length );
            array.push( renderItem );

        }

    }

    function finish() {

        opaque.length = opaqueLastIndex + 1;
        transparent.length = transparentLastIndex + 1;

    }

    function sort() {

        opaque.sort( painterSortStable );
        transparent.sort( reversePainterSortStable );

    }

    return {
        opaque: opaque,
        transparent: transparent,

        init: init,
        push: push,
        finish: finish,

        sort: sort
    };

}

function WebGLRenderLists() {

    var lists = {};

    function get( scene, camera ) {

        var hash = scene.id + ',' + camera.id;
        var list = lists[ hash ];

        if ( list === undefined ) {

            // console.log( 'THREE.WebGLRenderLists:', hash );

            list = new WebGLRenderList();
            lists[ hash ] = list;

        }

        return list;

    }

    function dispose() {

        lists = {};

    }

    return {
        get: get,
        dispose: dispose
    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {

    var mode;

    function setMode( value ) {

        mode = value;

    }

    var type, bytesPerElement;

    function setIndex( value ) {

        type = value.type;
        bytesPerElement = value.bytesPerElement;

    }

    function render( start, count ) {

        gl.drawElements( mode, count, type, start * bytesPerElement );

        infoRender.calls ++;
        infoRender.vertices += count;

        if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;

    }

    function renderInstances( geometry, start, count ) {

        var extension = extensions.get( 'ANGLE_instanced_arrays' );

        if ( extension === null ) {

            console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
            return;

        }

        extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );

        infoRender.calls ++;
        infoRender.vertices += count * geometry.maxInstancedCount;

        if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;

    }

    //

    this.setMode = setMode;
    this.setIndex = setIndex;
    this.render = render;
    this.renderInstances = renderInstances;

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLBufferRenderer( gl, extensions, infoRender ) {

    var mode;

    function setMode( value ) {

        mode = value;

    }

    function render( start, count ) {

        gl.drawArrays( mode, start, count );

        infoRender.calls ++;
        infoRender.vertices += count;

        if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;

    }

    function renderInstances( geometry, start, count ) {

        var extension = extensions.get( 'ANGLE_instanced_arrays' );

        if ( extension === null ) {

            console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
            return;

        }

        var position = geometry.attributes.position;

        if ( position.isInterleavedBufferAttribute ) {

            count = position.data.count;

            extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );

        } else {

            extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount );

        }

        infoRender.calls ++;
        infoRender.vertices += count * geometry.maxInstancedCount;

        if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;

    }

    //

    this.setMode = setMode;
    this.render = render;
    this.renderInstances = renderInstances;

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLGeometries( gl, attributes, infoMemory ) {

    var geometries = {};
    var wireframeAttributes = {};

    function onGeometryDispose( event ) {

        var geometry = event.target;
        var buffergeometry = geometries[ geometry.id ];

        if ( buffergeometry.index !== null ) {

            attributes.remove( buffergeometry.index );

        }

        for ( var name in buffergeometry.attributes ) {

            attributes.remove( buffergeometry.attributes[ name ] );

        }

        geometry.removeEventListener( 'dispose', onGeometryDispose );

        delete geometries[ geometry.id ];

        // TODO Remove duplicate code

        var attribute = wireframeAttributes[ geometry.id ];

        if ( attribute ) {

            attributes.remove( attribute );
            delete wireframeAttributes[ geometry.id ];

        }

        attribute = wireframeAttributes[ buffergeometry.id ];

        if ( attribute ) {

            attributes.remove( attribute );
            delete wireframeAttributes[ buffergeometry.id ];

        }

        //

        infoMemory.geometries --;

    }

    function get( object, geometry ) {

        var buffergeometry = geometries[ geometry.id ];

        if ( buffergeometry ) return buffergeometry;

        geometry.addEventListener( 'dispose', onGeometryDispose );

        if ( geometry.isBufferGeometry ) {

            buffergeometry = geometry;

        } else if ( geometry.isGeometry ) {

            if ( geometry._bufferGeometry === undefined ) {

                geometry._bufferGeometry = new BufferGeometry().setFromObject( object );

            }

            buffergeometry = geometry._bufferGeometry;

        }

        geometries[ geometry.id ] = buffergeometry;

        infoMemory.geometries ++;

        return buffergeometry;

    }

    function update( geometry ) {

        var index = geometry.index;
        var geometryAttributes = geometry.attributes;

        if ( index !== null ) {

            attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );

        }

        for ( var name in geometryAttributes ) {

            attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );

        }

        // morph targets

        var morphAttributes = geometry.morphAttributes;

        for ( var name in morphAttributes ) {

            var array = morphAttributes[ name ];

            for ( var i = 0, l = array.length; i < l; i ++ ) {

                attributes.update( array[ i ], gl.ARRAY_BUFFER );

            }

        }

    }

    function getWireframeAttribute( geometry ) {

        var attribute = wireframeAttributes[ geometry.id ];

        if ( attribute ) return attribute;

        var indices = [];

        var geometryIndex = geometry.index;
        var geometryAttributes = geometry.attributes;

        // console.time( 'wireframe' );

        if ( geometryIndex !== null ) {

            var array = geometryIndex.array;

            for ( var i = 0, l = array.length; i < l; i += 3 ) {

                var a = array[ i + 0 ];
                var b = array[ i + 1 ];
                var c = array[ i + 2 ];

                indices.push( a, b, b, c, c, a );

            }

        } else {

            var array = geometryAttributes.position.array;

            for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {

                var a = i + 0;
                var b = i + 1;
                var c = i + 2;

                indices.push( a, b, b, c, c, a );

            }

        }

        // console.timeEnd( 'wireframe' );

        attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );

        attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );

        wireframeAttributes[ geometry.id ] = attribute;

        return attribute;

    }

    return {

        get: get,
        update: update,

        getWireframeAttribute: getWireframeAttribute

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLLights() {

    var lights = {};

    return {

        get: function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            var uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color(),

                        shadow: false,
                        shadowBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0,

                        shadow: false,
                        shadowBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0,

                        shadow: false,
                        shadowBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                        // TODO (abelnation): set RectAreaLight shadow uniforms
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLObjects( gl, geometries, infoRender ) {

    var updateList = {};

    function update( object ) {

        var frame = infoRender.frame;

        var geometry = object.geometry;
        var buffergeometry = geometries.get( object, geometry );

        // Update once per frame

        if ( updateList[ buffergeometry.id ] !== frame ) {

            if ( geometry.isGeometry ) {

                buffergeometry.updateFromObject( object );

            }

            geometries.update( buffergeometry );

            updateList[ buffergeometry.id ] = frame;

        }

        return buffergeometry;

    }

    function clear() {

        updateList = {};

    }

    return {

        update: update,
        clear: clear

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function addLineNumbers( string ) {

    var lines = string.split( '\n' );

    for ( var i = 0; i < lines.length; i ++ ) {

        lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];

    }

    return lines.join( '\n' );

}

function WebGLShader( gl, type, string ) {

    var shader = gl.createShader( type );

    gl.shaderSource( shader, string );
    gl.compileShader( shader );

    if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {

        console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );

    }

    if ( gl.getShaderInfoLog( shader ) !== '' ) {

        console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );

    }

    // --enable-privileged-webgl-extension
    // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );

    return shader;

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

var programIdCount = 0;

function getEncodingComponents( encoding ) {

    switch ( encoding ) {

        case LinearEncoding:
            return [ 'Linear','( value )' ];
        case sRGBEncoding:
            return [ 'sRGB','( value )' ];
        case RGBEEncoding:
            return [ 'RGBE','( value )' ];
        case RGBM7Encoding:
            return [ 'RGBM','( value, 7.0 )' ];
        case RGBM16Encoding:
            return [ 'RGBM','( value, 16.0 )' ];
        case RGBDEncoding:
            return [ 'RGBD','( value, 256.0 )' ];
        case GammaEncoding:
            return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ];
        default:
            throw new Error( 'unsupported encoding: ' + encoding );

    }

}

function getTexelDecodingFunction( functionName, encoding ) {

    var components = getEncodingComponents( encoding );
    return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }";

}

function getTexelEncodingFunction( functionName, encoding ) {

    var components = getEncodingComponents( encoding );
    return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }";

}

function getToneMappingFunction( functionName, toneMapping ) {

    var toneMappingName;

    switch ( toneMapping ) {

        case LinearToneMapping:
            toneMappingName = "Linear";
            break;

        case ReinhardToneMapping:
            toneMappingName = "Reinhard";
            break;

        case Uncharted2ToneMapping:
            toneMappingName = "Uncharted2";
            break;

        case CineonToneMapping:
            toneMappingName = "OptimizedCineon";
            break;

        default:
            throw new Error( 'unsupported toneMapping: ' + toneMapping );

    }

    return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }";

}

function generateExtensions( extensions, parameters, rendererExtensions ) {

    extensions = extensions || {};

    var chunks = [
        ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
        ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
        ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
        ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
    ];

    return chunks.filter( filterEmptyLine ).join( '\n' );

}

function generateDefines( defines ) {

    var chunks = [];

    for ( var name in defines ) {

        var value = defines[ name ];

        if ( value === false ) continue;

        chunks.push( '#define ' + name + ' ' + value );

    }

    return chunks.join( '\n' );

}

function fetchAttributeLocations( gl, program, identifiers ) {

    var attributes = {};

    var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );

    for ( var i = 0; i < n; i ++ ) {

        var info = gl.getActiveAttrib( program, i );
        var name = info.name;

        // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i );

        attributes[ name ] = gl.getAttribLocation( program, name );

    }

    return attributes;

}

function filterEmptyLine( string ) {

    return string !== '';

}

function replaceLightNums( string, parameters ) {

    return string
        .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
        .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
        .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
        .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
        .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );

}

function parseIncludes( string ) {

    var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;

    function replace( match, include ) {

        var replace = ShaderChunk[ include ];

        if ( replace === undefined ) {

            throw new Error( 'Can not resolve #include <' + include + '>' );

        }

        return parseIncludes( replace );

    }

    return string.replace( pattern, replace );

}

function unrollLoops( string ) {

    var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;

    function replace( match, start, end, snippet ) {

        var unroll = '';

        for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {

            unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );

        }

        return unroll;

    }

    return string.replace( pattern, replace );

}

function WebGLProgram( renderer, code, material, shader, parameters ) {

    var gl = renderer.context;

    var extensions = material.extensions;
    var defines = material.defines;

    var vertexShader = shader.vertexShader;
    var fragmentShader = shader.fragmentShader;

    var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';

    if ( parameters.shadowMapType === PCFShadowMap ) {

        shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';

    } else if ( parameters.shadowMapType === 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 CubeReflectionMapping:
            case CubeRefractionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
                break;

            case CubeUVReflectionMapping:
            case CubeUVRefractionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
                break;

            case EquirectangularReflectionMapping:
            case EquirectangularRefractionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
                break;

            case SphericalReflectionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
                break;

        }

        switch ( material.envMap.mapping ) {

            case CubeRefractionMapping:
            case EquirectangularRefractionMapping:
                envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
                break;

        }

        switch ( material.combine ) {

            case MultiplyOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
                break;

            case MixOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
                break;

            case AddOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
                break;

        }

    }

    var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;

    // console.log( 'building new program ' );

    //

    var customExtensions = generateExtensions( extensions, parameters, renderer.extensions );

    var customDefines = generateDefines( defines );

    //

    var program = gl.createProgram();

    var prefixVertex, prefixFragment;

    if ( material.isRawShaderMaterial ) {

        prefixVertex = [

            customDefines,

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

        prefixFragment = [

            customExtensions,
            customDefines,

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

    } else {

        prefixVertex = [

            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',

            '#define SHADER_NAME ' + shader.name,

            customDefines,

            parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',

            '#define GAMMA_FACTOR ' + gammaFactorDefine,

            '#define MAX_BONES ' + parameters.maxBones,
            ( 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 ' + envMapModeDefine : '',
            parameters.lightMap ? '#define USE_LIGHTMAP' : '',
            parameters.aoMap ? '#define USE_AOMAP' : '',
            parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
            parameters.bumpMap ? '#define USE_BUMPMAP' : '',
            parameters.normalMap ? '#define USE_NORMALMAP' : '',
            parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
            parameters.specularMap ? '#define USE_SPECULARMAP' : '',
            parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
            parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
            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 && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
            parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
            parameters.flipSided ? '#define FLIP_SIDED' : '',

            '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,

            parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
            parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',

            parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',

            parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
            parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#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;',

            '#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',

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

        prefixFragment = [

            customExtensions,

            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',

            '#define SHADER_NAME ' + shader.name,

            customDefines,

            parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',

            '#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.aoMap ? '#define USE_AOMAP' : '',
            parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
            parameters.bumpMap ? '#define USE_BUMPMAP' : '',
            parameters.normalMap ? '#define USE_NORMALMAP' : '',
            parameters.specularMap ? '#define USE_SPECULARMAP' : '',
            parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
            parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
            parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
            parameters.vertexColors ? '#define USE_COLOR' : '',

            parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',

            parameters.flatShading ? '#define FLAT_SHADED' : '',

            parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
            parameters.flipSided ? '#define FLIP_SIDED' : '',

            '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
            '#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),

            parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
            parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',

            parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '',

            parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '',

            parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
            parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',

            parameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',

            'uniform mat4 viewMatrix;',
            'uniform vec3 cameraPosition;',

            ( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '',
            ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '',  // this code is required here because it is used by the toneMapping() function defined below
            ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '',

            parameters.dithering ? '#define DITHERING' : '',

            ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
            parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
            parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
            parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
            parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '',

            parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '',

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

    }

    vertexShader = parseIncludes( vertexShader );
    vertexShader = replaceLightNums( vertexShader, parameters );

    fragmentShader = parseIncludes( fragmentShader );
    fragmentShader = replaceLightNums( fragmentShader, parameters );

    if ( ! material.isShaderMaterial ) {

        vertexShader = unrollLoops( vertexShader );
        fragmentShader = unrollLoops( fragmentShader );

    }

    var vertexGlsl = prefixVertex + vertexShader;
    var fragmentGlsl = prefixFragment + fragmentShader;

    // console.log( '*VERTEX*', vertexGlsl );
    // console.log( '*FRAGMENT*', fragmentGlsl );

    var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
    var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );

    gl.attachShader( program, glVertexShader );
    gl.attachShader( program, glFragmentShader );

    // Force a particular attribute to index 0.

    if ( material.index0AttributeName !== undefined ) {

        gl.bindAttribLocation( program, 0, material.index0AttributeName );

    } else if ( parameters.morphTargets === true ) {

        // programs with morphTargets displace position out of attribute 0
        gl.bindAttribLocation( program, 0, 'position' );

    }

    gl.linkProgram( program );

    var programLog = gl.getProgramInfoLog( program );
    var vertexLog = gl.getShaderInfoLog( glVertexShader );
    var fragmentLog = gl.getShaderInfoLog( glFragmentShader );

    var runnable = true;
    var haveDiagnostics = true;

    // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
    // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );

    if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {

        runnable = false;

        console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );

    } else if ( programLog !== '' ) {

        console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );

    } else if ( vertexLog === '' || fragmentLog === '' ) {

        haveDiagnostics = false;

    }

    if ( haveDiagnostics ) {

        this.diagnostics = {

            runnable: runnable,
            material: material,

            programLog: programLog,

            vertexShader: {

                log: vertexLog,
                prefix: prefixVertex

            },

            fragmentShader: {

                log: fragmentLog,
                prefix: prefixFragment

            }

        };

    }

    // clean up

    gl.deleteShader( glVertexShader );
    gl.deleteShader( glFragmentShader );

    // set up caching for uniform locations

    var cachedUniforms;

    this.getUniforms = function() {

        if ( cachedUniforms === undefined ) {

            cachedUniforms =
                new WebGLUniforms( gl, program, renderer );

        }

        return cachedUniforms;

    };

    // set up caching for attribute locations

    var cachedAttributes;

    this.getAttributes = function() {

        if ( cachedAttributes === undefined ) {

            cachedAttributes = fetchAttributeLocations( gl, program );

        }

        return cachedAttributes;

    };

    // free resource

    this.destroy = function() {

        gl.deleteProgram( program );
        this.program = undefined;

    };

    // DEPRECATED

    Object.defineProperties( this, {

        uniforms: {
            get: function() {

                console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
                return this.getUniforms();

            }
        },

        attributes: {
            get: function() {

                console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
                return this.getAttributes();

            }
        }

    } );


    //

    this.id = programIdCount ++;
    this.code = code;
    this.usedTimes = 1;
    this.program = program;
    this.vertexShader = glVertexShader;
    this.fragmentShader = glFragmentShader;

    return this;

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLPrograms( renderer, capabilities ) {

    var programs = [];

    var shaderIDs = {
        MeshDepthMaterial: 'depth',
        MeshNormalMaterial: 'normal',
        MeshBasicMaterial: 'basic',
        MeshLambertMaterial: 'lambert',
        MeshPhongMaterial: 'phong',
        MeshToonMaterial: 'phong',
        MeshStandardMaterial: 'physical',
        MeshPhysicalMaterial: 'physical',
        LineBasicMaterial: 'basic',
        LineDashedMaterial: 'dashed',
        PointsMaterial: 'points'
    };

    var parameterNames = [
        "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
        "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
        "roughnessMap", "metalnessMap", "gradientMap",
        "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
        "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
        "maxBones", "useVertexTexture", "morphTargets", "morphNormals",
        "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
        "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
        "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
        "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
    ];


    function allocateBones( object ) {

        var skeleton = object.skeleton;
        var bones = skeleton.bones;

        if ( capabilities.floatVertexTextures ) {

            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 = capabilities.maxVertexUniforms;
            var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );

            var maxBones = Math.min( nVertexMatrices, bones.length );

            if ( maxBones < bones.length ) {

                console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
                return 0;

            }

            return maxBones;

        }

    }

    function getTextureEncodingFromMap( map, gammaOverrideLinear ) {

        var encoding;

        if ( ! map ) {

            encoding = LinearEncoding;

        } else if ( map.isTexture ) {

            encoding = map.encoding;

        } else if ( map.isWebGLRenderTarget ) {

            console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
            encoding = map.texture.encoding;

        }

        // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
        if ( encoding === LinearEncoding && gammaOverrideLinear ) {

            encoding = GammaEncoding;

        }

        return encoding;

    }

    this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {

        var shaderID = shaderIDs[ material.type ];

        // heuristics to create shader parameters according to lights in the scene
        // (not to blow over maxLights budget)

        var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
        var precision = renderer.getPrecision();

        if ( material.precision !== null ) {

            precision = capabilities.getMaxPrecision( material.precision );

            if ( precision !== material.precision ) {

                console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );

            }

        }

        var currentRenderTarget = renderer.getRenderTarget();

        var parameters = {

            shaderID: shaderID,

            precision: precision,
            supportsVertexTextures: capabilities.vertexTextures,
            outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
            map: !! material.map,
            mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
            envMap: !! material.envMap,
            envMapMode: material.envMap && material.envMap.mapping,
            envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
            envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
            lightMap: !! material.lightMap,
            aoMap: !! material.aoMap,
            emissiveMap: !! material.emissiveMap,
            emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
            bumpMap: !! material.bumpMap,
            normalMap: !! material.normalMap,
            displacementMap: !! material.displacementMap,
            roughnessMap: !! material.roughnessMap,
            metalnessMap: !! material.metalnessMap,
            specularMap: !! material.specularMap,
            alphaMap: !! material.alphaMap,

            gradientMap: !! material.gradientMap,

            combine: material.combine,

            vertexColors: material.vertexColors,

            fog: !! fog,
            useFog: material.fog,
            fogExp: ( fog && fog.isFogExp2 ),

            flatShading: material.shading === FlatShading,

            sizeAttenuation: material.sizeAttenuation,
            logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,

            skinning: material.skinning && maxBones > 0,
            maxBones: maxBones,
            useVertexTexture: capabilities.floatVertexTextures,

            morphTargets: material.morphTargets,
            morphNormals: material.morphNormals,
            maxMorphTargets: renderer.maxMorphTargets,
            maxMorphNormals: renderer.maxMorphNormals,

            numDirLights: lights.directional.length,
            numPointLights: lights.point.length,
            numSpotLights: lights.spot.length,
            numRectAreaLights: lights.rectArea.length,
            numHemiLights: lights.hemi.length,

            numClippingPlanes: nClipPlanes,
            numClipIntersection: nClipIntersection,

            dithering: material.dithering,

            shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
            shadowMapType: renderer.shadowMap.type,

            toneMapping: renderer.toneMapping,
            physicallyCorrectLights: renderer.physicallyCorrectLights,

            premultipliedAlpha: material.premultipliedAlpha,

            alphaTest: material.alphaTest,
            doubleSided: material.side === DoubleSide,
            flipSided: material.side === BackSide,

            depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false

        };

        return parameters;

    };

    this.getProgramCode = function ( material, parameters ) {

        var array = [];

        if ( parameters.shaderID ) {

            array.push( parameters.shaderID );

        } else {

            array.push( material.fragmentShader );
            array.push( material.vertexShader );

        }

        if ( material.defines !== undefined ) {

            for ( var name in material.defines ) {

                array.push( name );
                array.push( material.defines[ name ] );

            }

        }

        for ( var i = 0; i < parameterNames.length; i ++ ) {

            array.push( parameters[ parameterNames[ i ] ] );

        }

        array.push( material.onBeforeCompile.toString() );

        array.push( renderer.gammaOutput );

        return array.join();

    };

    this.acquireProgram = function ( material, shader, parameters, code ) {

        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 WebGLProgram( renderer, code, material, shader, parameters );
            programs.push( program );

        }

        return program;

    };

    this.releaseProgram = function ( program ) {

        if ( -- program.usedTimes === 0 ) {

            // Remove from unordered set
            var i = programs.indexOf( program );
            programs[ i ] = programs[ programs.length - 1 ];
            programs.pop();

            // Free WebGL resources
            program.destroy();

        }

    };

    // Exposed for resource monitoring & error feedback via renderer.info:
    this.programs = programs;

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, infoMemory ) {

    var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );

    //

    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.createElementNS( 'http://www.w3.org/1999/xhtml', '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 );

            console.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 isPowerOfTwo( image ) {

        return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );

    }

    function makePowerOfTwo( image ) {

        if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) {

            var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
            canvas.width = _Math.nearestPowerOfTwo( image.width );
            canvas.height = _Math.nearestPowerOfTwo( image.height );

            var context = canvas.getContext( '2d' );
            context.drawImage( image, 0, 0, canvas.width, canvas.height );

            console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );

            return canvas;

        }

        return image;

    }

    function textureNeedsPowerOfTwo( texture ) {

        return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
            ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );

    }

    function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {

        return texture.generateMipmaps && isPowerOfTwo &&
            texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;

    }

    // Fallback filters for non-power-of-2 textures

    function filterFallback( f ) {

        if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {

            return _gl.NEAREST;

        }

        return _gl.LINEAR;

    }

    //

    function onTextureDispose( event ) {

        var texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        deallocateTexture( texture );

        infoMemory.textures --;


    }

    function onRenderTargetDispose( event ) {

        var renderTarget = event.target;

        renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );

        deallocateRenderTarget( renderTarget );

        infoMemory.textures --;

    }

    //

    function deallocateTexture( texture ) {

        var textureProperties = properties.get( texture );

        if ( texture.image && textureProperties.__image__webglTextureCube ) {

            // cube texture

            _gl.deleteTexture( textureProperties.__image__webglTextureCube );

        } else {

            // 2D texture

            if ( textureProperties.__webglInit === undefined ) return;

            _gl.deleteTexture( textureProperties.__webglTexture );

        }

        // remove all webgl properties
        properties.remove( texture );

    }

    function deallocateRenderTarget( renderTarget ) {

        var renderTargetProperties = properties.get( renderTarget );
        var textureProperties = properties.get( renderTarget.texture );

        if ( ! renderTarget ) return;

        if ( textureProperties.__webglTexture !== undefined ) {

            _gl.deleteTexture( textureProperties.__webglTexture );

        }

        if ( renderTarget.depthTexture ) {

            renderTarget.depthTexture.dispose();

        }

        if ( renderTarget.isWebGLRenderTargetCube ) {

            for ( var i = 0; i < 6; i ++ ) {

                _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
                if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );

            }

        } else {

            _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
            if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );

        }

        properties.remove( renderTarget.texture );
        properties.remove( renderTarget );

    }

    //



    function setTexture2D( texture, slot ) {

        var textureProperties = properties.get( texture );

        if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

            var image = texture.image;

            if ( image === undefined ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );

            } else if ( image.complete === false ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );

            } else {

                uploadTexture( textureProperties, texture, slot );
                return;

            }

        }

        state.activeTexture( _gl.TEXTURE0 + slot );
        state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );

    }

    function setTextureCube( texture, slot ) {

        var textureProperties = properties.get( texture );

        if ( texture.image.length === 6 ) {

            if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

                if ( ! textureProperties.__image__webglTextureCube ) {

                    texture.addEventListener( 'dispose', onTextureDispose );

                    textureProperties.__image__webglTextureCube = _gl.createTexture();

                    infoMemory.textures ++;

                }

                state.activeTexture( _gl.TEXTURE0 + slot );
                state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );

                _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );

                var isCompressed = ( texture && texture.isCompressedTexture );
                var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );

                var cubeImage = [];

                for ( var i = 0; i < 6; i ++ ) {

                    if ( ! isCompressed && ! isDataTexture ) {

                        cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );

                    } else {

                        cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];

                    }

                }

                var image = cubeImage[ 0 ],
                isPowerOfTwoImage = isPowerOfTwo( image ),
                glFormat = paramThreeToGL( texture.format ),
                glType = paramThreeToGL( texture.type );

                setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );

                for ( var i = 0; i < 6; i ++ ) {

                    if ( ! isCompressed ) {

                        if ( isDataTexture ) {

                            state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );

                        } else {

                            state.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 !== RGBAFormat && texture.format !== RGBFormat ) {

                                if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {

                                    state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                                } else {

                                    console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()" );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                }

                if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {

                    _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );

                }

                textureProperties.__version = texture.version;

                if ( texture.onUpdate ) texture.onUpdate( texture );

            } else {

                state.activeTexture( _gl.TEXTURE0 + slot );
                state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );

            }

        }

    }

    function setTextureCubeDynamic( texture, slot ) {

        state.activeTexture( _gl.TEXTURE0 + slot );
        state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );

    }

    function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {

        var extension;

        if ( isPowerOfTwoImage ) {

            _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 !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {

                console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );

            }

            _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
            _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );

            if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {

                console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );

            }

        }

        extension = extensions.get( 'EXT_texture_filter_anisotropic' );

        if ( extension ) {

            if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
            if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;

            if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {

                _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
                properties.get( texture ).__currentAnisotropy = texture.anisotropy;

            }

        }

    }

    function uploadTexture( textureProperties, texture, slot ) {

        if ( textureProperties.__webglInit === undefined ) {

            textureProperties.__webglInit = true;

            texture.addEventListener( 'dispose', onTextureDispose );

            textureProperties.__webglTexture = _gl.createTexture();

            infoMemory.textures ++;

        }

        state.activeTexture( _gl.TEXTURE0 + slot );
        state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );

        _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
        _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
        _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );

        var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );

        if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {

            image = makePowerOfTwo( image );

        }

        var isPowerOfTwoImage = isPowerOfTwo( image ),
        glFormat = paramThreeToGL( texture.format ),
        glType = paramThreeToGL( texture.type );

        setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );

        var mipmap, mipmaps = texture.mipmaps;

        if ( texture.isDepthTexture ) {

            // populate depth texture with dummy data

            var internalFormat = _gl.DEPTH_COMPONENT;

            if ( texture.type === FloatType ) {

                if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0');
                internalFormat = _gl.DEPTH_COMPONENT32F;

            } else if ( _isWebGL2 ) {

                // WebGL 2.0 requires signed internalformat for glTexImage2D
                internalFormat = _gl.DEPTH_COMPONENT16;

            }

            if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {

                // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
                // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
                // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
                if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {

                        console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );

                    texture.type = UnsignedShortType;
                    glType = paramThreeToGL( texture.type );

                }

            }

            // Depth stencil textures need the DEPTH_STENCIL internal format
            // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
            if ( texture.format === DepthStencilFormat ) {

                internalFormat = _gl.DEPTH_STENCIL;

                // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
                // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
                // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
                if ( texture.type !== UnsignedInt248Type ) {

                    console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );

                    texture.type = UnsignedInt248Type;
                    glType = paramThreeToGL( texture.type );

                }

            }

            state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );

        } else if ( texture.isDataTexture ) {

            // 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 && isPowerOfTwoImage ) {

                for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

                    mipmap = mipmaps[ i ];
                    state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                }

                texture.generateMipmaps = false;

            } else {

                state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );

            }

        } else if ( texture.isCompressedTexture ) {

            for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

                mipmap = mipmaps[ i ];

                if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {

                    if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {

                        state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                    } else {

                        console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" );

                    }

                } else {

                    state.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 && isPowerOfTwoImage ) {

                for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

                    mipmap = mipmaps[ i ];
                    state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );

                }

                texture.generateMipmaps = false;

            } else {

                state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );

            }

        }

        if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D );

        textureProperties.__version = texture.version;

        if ( texture.onUpdate ) texture.onUpdate( texture );

    }

    // Render targets

    // Setup storage for target texture and bind it to correct framebuffer
    function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {

        var glFormat = paramThreeToGL( renderTarget.texture.format );
        var glType = paramThreeToGL( renderTarget.texture.type );
        state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
        _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
        _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
        _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

    // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
    function setupRenderBufferStorage( 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 );

        } 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 {

            // FIXME: We don't support !depth !stencil
            _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );

        }

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

    }

    // Setup resources for a Depth Texture for a FBO (needs an extension)
    function setupDepthTexture( framebuffer, renderTarget ) {

        var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
        if ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!');

        _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

        if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {

            throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture');

        }

        // upload an empty depth texture with framebuffer size
        if ( !properties.get( renderTarget.depthTexture ).__webglTexture ||
                renderTarget.depthTexture.image.width !== renderTarget.width ||
                renderTarget.depthTexture.image.height !== renderTarget.height ) {
            renderTarget.depthTexture.image.width = renderTarget.width;
            renderTarget.depthTexture.image.height = renderTarget.height;
            renderTarget.depthTexture.needsUpdate = true;
        }

        setTexture2D( renderTarget.depthTexture, 0 );

        var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;

        if ( renderTarget.depthTexture.format === DepthFormat ) {

            _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

        } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {

            _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

        } else {

            throw new Error('Unknown depthTexture format')

        }

    }

    // Setup GL resources for a non-texture depth buffer
    function setupDepthRenderbuffer( renderTarget ) {

        var renderTargetProperties = properties.get( renderTarget );

        var isCube = ( renderTarget.isWebGLRenderTargetCube === true );

        if ( renderTarget.depthTexture ) {

            if ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets');

            setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );

        } else {

            if ( isCube ) {

                renderTargetProperties.__webglDepthbuffer = [];

                for ( var i = 0; i < 6; i ++ ) {

                    _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
                    renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
                    setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );

                }

            } else {

                _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
                renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
                setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );

            }

        }

        _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

    // Set up GL resources for the render target
    function setupRenderTarget( renderTarget ) {

        var renderTargetProperties = properties.get( renderTarget );
        var textureProperties = properties.get( renderTarget.texture );

        renderTarget.addEventListener( 'dispose', onRenderTargetDispose );

        textureProperties.__webglTexture = _gl.createTexture();

        infoMemory.textures ++;

        var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
        var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );

        // Setup framebuffer

        if ( isCube ) {

            renderTargetProperties.__webglFramebuffer = [];

            for ( var i = 0; i < 6; i ++ ) {

                renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();

            }

        } else {

            renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();

        }

        // Setup color buffer

        if ( isCube ) {

            state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
            setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );

            for ( var i = 0; i < 6; i ++ ) {

                setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );

            }

            if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
            state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );

        } else {

            state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
            setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
            setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );

            if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D );
            state.bindTexture( _gl.TEXTURE_2D, null );

        }

        // Setup depth and stencil buffers

        if ( renderTarget.depthBuffer ) {

            setupDepthRenderbuffer( renderTarget );

        }

    }

    function updateRenderTargetMipmap( renderTarget ) {

        var texture = renderTarget.texture;
        var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );

        if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {

            var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
            var webglTexture = properties.get( texture ).__webglTexture;

            state.bindTexture( target, webglTexture );
            _gl.generateMipmap( target );
            state.bindTexture( target, null );

        }

    }

    this.setTexture2D = setTexture2D;
    this.setTextureCube = setTextureCube;
    this.setTextureCubeDynamic = setTextureCubeDynamic;
    this.setupRenderTarget = setupRenderTarget;
    this.updateRenderTargetMipmap = updateRenderTargetMipmap;

}

/**
 * @author fordacious / fordacious.github.io
 */

function WebGLProperties() {

    var properties = {};

    function get( object ) {

        var uuid = object.uuid;
        var map = properties[ uuid ];

        if ( map === undefined ) {

            map = {};
            properties[ uuid ] = map;

        }

        return map;

    }

    function remove( object ) {

        delete properties[ object.uuid ];

    }

    function clear() {

        properties = {};

    }

    return {
        get: get,
        remove: remove,
        clear: clear
    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLState( gl, extensions, paramThreeToGL ) {

    function ColorBuffer() {

        var locked = false;

        var color = new Vector4();
        var currentColorMask = null;
        var currentColorClear = new Vector4();

        return {

            setMask: function ( colorMask ) {

                if ( currentColorMask !== colorMask && ! locked ) {

                    gl.colorMask( colorMask, colorMask, colorMask, colorMask );
                    currentColorMask = colorMask;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( r, g, b, a, premultipliedAlpha ) {

                if ( premultipliedAlpha === true ) {

                    r *= a; g *= a; b *= a;

                }

                color.set( r, g, b, a );

                if ( currentColorClear.equals( color ) === false ) {

                    gl.clearColor( r, g, b, a );
                    currentColorClear.copy( color );

                }

            },

            reset: function () {

                locked = false;

                currentColorMask = null;
                currentColorClear.set( 0, 0, 0, 1 );

            }

        };

    }

    function DepthBuffer() {

        var locked = false;

        var currentDepthMask = null;
        var currentDepthFunc = null;
        var currentDepthClear = null;

        return {

            setTest: function ( depthTest ) {

                if ( depthTest ) {

                    enable( gl.DEPTH_TEST );

                } else {

                    disable( gl.DEPTH_TEST );

                }

            },

            setMask: function ( depthMask ) {

                if ( currentDepthMask !== depthMask && ! locked ) {

                    gl.depthMask( depthMask );
                    currentDepthMask = depthMask;

                }

            },

            setFunc: function ( depthFunc ) {

                if ( currentDepthFunc !== depthFunc ) {

                    if ( depthFunc ) {

                        switch ( depthFunc ) {

                            case NeverDepth:

                                gl.depthFunc( gl.NEVER );
                                break;

                            case AlwaysDepth:

                                gl.depthFunc( gl.ALWAYS );
                                break;

                            case LessDepth:

                                gl.depthFunc( gl.LESS );
                                break;

                            case LessEqualDepth:

                                gl.depthFunc( gl.LEQUAL );
                                break;

                            case EqualDepth:

                                gl.depthFunc( gl.EQUAL );
                                break;

                            case GreaterEqualDepth:

                                gl.depthFunc( gl.GEQUAL );
                                break;

                            case GreaterDepth:

                                gl.depthFunc( gl.GREATER );
                                break;

                            case NotEqualDepth:

                                gl.depthFunc( gl.NOTEQUAL );
                                break;

                            default:

                                gl.depthFunc( gl.LEQUAL );

                        }

                    } else {

                        gl.depthFunc( gl.LEQUAL );

                    }

                    currentDepthFunc = depthFunc;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( depth ) {

                if ( currentDepthClear !== depth ) {

                    gl.clearDepth( depth );
                    currentDepthClear = depth;

                }

            },

            reset: function () {

                locked = false;

                currentDepthMask = null;
                currentDepthFunc = null;
                currentDepthClear = null;

            }

        };

    }

    function StencilBuffer() {

        var locked = false;

        var currentStencilMask = null;
        var currentStencilFunc = null;
        var currentStencilRef = null;
        var currentStencilFuncMask = null;
        var currentStencilFail = null;
        var currentStencilZFail = null;
        var currentStencilZPass = null;
        var currentStencilClear = null;

        return {

            setTest: function ( stencilTest ) {

                if ( stencilTest ) {

                    enable( gl.STENCIL_TEST );

                } else {

                    disable( gl.STENCIL_TEST );

                }

            },

            setMask: function ( stencilMask ) {

                if ( currentStencilMask !== stencilMask && ! locked ) {

                    gl.stencilMask( stencilMask );
                    currentStencilMask = stencilMask;

                }

            },

            setFunc: function ( stencilFunc, stencilRef, stencilMask ) {

                if ( currentStencilFunc !== stencilFunc ||
                     currentStencilRef     !== stencilRef     ||
                     currentStencilFuncMask !== stencilMask ) {

                    gl.stencilFunc( stencilFunc, stencilRef, stencilMask );

                    currentStencilFunc = stencilFunc;
                    currentStencilRef = stencilRef;
                    currentStencilFuncMask = stencilMask;

                }

            },

            setOp: function ( stencilFail, stencilZFail, stencilZPass ) {

                if ( currentStencilFail     !== stencilFail     ||
                     currentStencilZFail !== stencilZFail ||
                     currentStencilZPass !== stencilZPass ) {

                    gl.stencilOp( stencilFail, stencilZFail, stencilZPass );

                    currentStencilFail = stencilFail;
                    currentStencilZFail = stencilZFail;
                    currentStencilZPass = stencilZPass;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( stencil ) {

                if ( currentStencilClear !== stencil ) {

                    gl.clearStencil( stencil );
                    currentStencilClear = stencil;

                }

            },

            reset: function () {

                locked = false;

                currentStencilMask = null;
                currentStencilFunc = null;
                currentStencilRef = null;
                currentStencilFuncMask = null;
                currentStencilFail = null;
                currentStencilZFail = null;
                currentStencilZPass = null;
                currentStencilClear = null;

            }

        };

    }

    //

    var colorBuffer = new ColorBuffer();
    var depthBuffer = new DepthBuffer();
    var stencilBuffer = new StencilBuffer();

    var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
    var newAttributes = new Uint8Array( maxVertexAttributes );
    var enabledAttributes = new Uint8Array( maxVertexAttributes );
    var attributeDivisors = new Uint8Array( maxVertexAttributes );

    var capabilities = {};

    var compressedTextureFormats = null;

    var currentBlending = null;
    var currentBlendEquation = null;
    var currentBlendSrc = null;
    var currentBlendDst = null;
    var currentBlendEquationAlpha = null;
    var currentBlendSrcAlpha = null;
    var currentBlendDstAlpha = null;
    var currentPremultipledAlpha = false;

    var currentFlipSided = null;
    var currentCullFace = null;

    var currentLineWidth = null;

    var currentPolygonOffsetFactor = null;
    var currentPolygonOffsetUnits = null;

    var currentScissorTest = null;

    var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );

    var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );
    var lineWidthAvailable = parseFloat( version ) >= 1.0;

    var currentTextureSlot = null;
    var currentBoundTextures = {};

    var currentScissor = new Vector4();
    var currentViewport = new Vector4();

    function createTexture( type, target, count ) {

        var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
        var texture = gl.createTexture();

        gl.bindTexture( type, texture );
        gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
        gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );

        for ( var i = 0; i < count; i ++ ) {

            gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );

        }

        return texture;

    }

    var emptyTextures = {};
    emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
    emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );

    //

    function init() {

        colorBuffer.setClear( 0, 0, 0, 1 );
        depthBuffer.setClear( 1 );
        stencilBuffer.setClear( 0 );

        enable( gl.DEPTH_TEST );
        depthBuffer.setFunc( LessEqualDepth );

        setFlipSided( false );
        setCullFace( CullFaceBack );
        enable( gl.CULL_FACE );

        enable( gl.BLEND );
        setBlending( NormalBlending );

    }

    function initAttributes() {

        for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {

            newAttributes[ i ] = 0;

        }

    }

    function enableAttribute( attribute ) {

        newAttributes[ attribute ] = 1;

        if ( enabledAttributes[ attribute ] === 0 ) {

            gl.enableVertexAttribArray( attribute );
            enabledAttributes[ attribute ] = 1;

        }

        if ( attributeDivisors[ attribute ] !== 0 ) {

            var extension = extensions.get( 'ANGLE_instanced_arrays' );

            extension.vertexAttribDivisorANGLE( attribute, 0 );
            attributeDivisors[ attribute ] = 0;

        }

    }

    function enableAttributeAndDivisor( attribute, meshPerAttribute ) {

        newAttributes[ attribute ] = 1;

        if ( enabledAttributes[ attribute ] === 0 ) {

            gl.enableVertexAttribArray( attribute );
            enabledAttributes[ attribute ] = 1;

        }

        if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {

            var extension = extensions.get( 'ANGLE_instanced_arrays' );

            extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );
            attributeDivisors[ attribute ] = meshPerAttribute;

        }

    }

    function disableUnusedAttributes() {

        for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {

            if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {

                gl.disableVertexAttribArray( i );
                enabledAttributes[ i ] = 0;

            }

        }

    }

    function enable( id ) {

        if ( capabilities[ id ] !== true ) {

            gl.enable( id );
            capabilities[ id ] = true;

        }

    }

    function disable( id ) {

        if ( capabilities[ id ] !== false ) {

            gl.disable( id );
            capabilities[ id ] = false;

        }

    }

    function getCompressedTextureFormats() {

        if ( compressedTextureFormats === null ) {

            compressedTextureFormats = [];

            if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
                 extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
                 extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {

                var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );

                for ( var i = 0; i < formats.length; i ++ ) {

                    compressedTextureFormats.push( formats[ i ] );

                }

            }

        }

        return compressedTextureFormats;

    }

    function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {

        if ( blending !== NoBlending ) {

            enable( gl.BLEND );

        } else {

            disable( gl.BLEND );

        }

        if ( ( blending !== CustomBlending ) && ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) ) {

            if ( blending === AdditiveBlending ) {

                if ( premultipliedAlpha ) {

                    gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
                    gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );

                } else {

                    gl.blendEquation( gl.FUNC_ADD );
                    gl.blendFunc( gl.SRC_ALPHA, gl.ONE );

                }

            } else if ( blending === SubtractiveBlending ) {

                if ( premultipliedAlpha ) {

                    gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
                    gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );

                } else {

                    gl.blendEquation( gl.FUNC_ADD );
                    gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );

                }

            } else if ( blending === MultiplyBlending ) {

                if ( premultipliedAlpha ) {

                    gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
                    gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );

                } else {

                    gl.blendEquation( gl.FUNC_ADD );
                    gl.blendFunc( gl.ZERO, gl.SRC_COLOR );

                }

            } else {

                if ( premultipliedAlpha ) {

                    gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
                    gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );

                } else {

                    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;
            currentPremultipledAlpha = premultipliedAlpha;

        }

        if ( blending === 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;

        }

    }

    function setMaterial( material ) {

        material.side === DoubleSide
            ? disable( gl.CULL_FACE )
            : enable( gl.CULL_FACE );

        setFlipSided( material.side === BackSide );

        material.transparent === true
            ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
            : setBlending( NoBlending );

        depthBuffer.setFunc( material.depthFunc );
        depthBuffer.setTest( material.depthTest );
        depthBuffer.setMask( material.depthWrite );
        colorBuffer.setMask( material.colorWrite );

        setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

    }

    //

    function setFlipSided( flipSided ) {

        if ( currentFlipSided !== flipSided ) {

            if ( flipSided ) {

                gl.frontFace( gl.CW );

            } else {

                gl.frontFace( gl.CCW );

            }

            currentFlipSided = flipSided;

        }

    }

    function setCullFace( cullFace ) {

        if ( cullFace !== CullFaceNone ) {

            enable( gl.CULL_FACE );

            if ( cullFace !== currentCullFace ) {

                if ( cullFace === CullFaceBack ) {

                    gl.cullFace( gl.BACK );

                } else if ( cullFace === CullFaceFront ) {

                    gl.cullFace( gl.FRONT );

                } else {

                    gl.cullFace( gl.FRONT_AND_BACK );

                }

            }

        } else {

            disable( gl.CULL_FACE );

        }

        currentCullFace = cullFace;

    }

    function setLineWidth( width ) {

        if ( width !== currentLineWidth ) {

            if ( lineWidthAvailable ) gl.lineWidth( width );

            currentLineWidth = width;

        }

    }

    function setPolygonOffset( polygonOffset, factor, units ) {

        if ( polygonOffset ) {

            enable( gl.POLYGON_OFFSET_FILL );

            if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {

                gl.polygonOffset( factor, units );

                currentPolygonOffsetFactor = factor;
                currentPolygonOffsetUnits = units;

            }

        } else {

            disable( gl.POLYGON_OFFSET_FILL );

        }

    }

    function getScissorTest() {

        return currentScissorTest;

    }

    function setScissorTest( scissorTest ) {

        currentScissorTest = scissorTest;

        if ( scissorTest ) {

            enable( gl.SCISSOR_TEST );

        } else {

            disable( gl.SCISSOR_TEST );

        }

    }

    // texture

    function activeTexture( webglSlot ) {

        if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;

        if ( currentTextureSlot !== webglSlot ) {

            gl.activeTexture( webglSlot );
            currentTextureSlot = webglSlot;

        }

    }

    function bindTexture( webglType, webglTexture ) {

        if ( currentTextureSlot === null ) {

            activeTexture();

        }

        var boundTexture = currentBoundTextures[ currentTextureSlot ];

        if ( boundTexture === undefined ) {

            boundTexture = { type: undefined, texture: undefined };
            currentBoundTextures[ currentTextureSlot ] = boundTexture;

        }

        if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {

            gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );

            boundTexture.type = webglType;
            boundTexture.texture = webglTexture;

        }

    }

    function compressedTexImage2D() {

        try {

            gl.compressedTexImage2D.apply( gl, arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texImage2D() {

        try {

            gl.texImage2D.apply( gl, arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    //

    function scissor( scissor ) {

        if ( currentScissor.equals( scissor ) === false ) {

            gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
            currentScissor.copy( scissor );

        }

    }

    function viewport( viewport ) {

        if ( currentViewport.equals( viewport ) === false ) {

            gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
            currentViewport.copy( viewport );

        }

    }

    //

    function reset() {

        for ( var i = 0; i < enabledAttributes.length; i ++ ) {

            if ( enabledAttributes[ i ] === 1 ) {

                gl.disableVertexAttribArray( i );
                enabledAttributes[ i ] = 0;

            }

        }

        capabilities = {};

        compressedTextureFormats = null;

        currentTextureSlot = null;
        currentBoundTextures = {};

        currentBlending = null;

        currentFlipSided = null;
        currentCullFace = null;

        colorBuffer.reset();
        depthBuffer.reset();
        stencilBuffer.reset();

    }

    return {

        buffers: {
            color: colorBuffer,
            depth: depthBuffer,
            stencil: stencilBuffer
        },

        init: init,
        initAttributes: initAttributes,
        enableAttribute: enableAttribute,
        enableAttributeAndDivisor: enableAttributeAndDivisor,
        disableUnusedAttributes: disableUnusedAttributes,
        enable: enable,
        disable: disable,
        getCompressedTextureFormats: getCompressedTextureFormats,

        setBlending: setBlending,
        setMaterial: setMaterial,

        setFlipSided: setFlipSided,
        setCullFace: setCullFace,

        setLineWidth: setLineWidth,
        setPolygonOffset: setPolygonOffset,

        getScissorTest: getScissorTest,
        setScissorTest: setScissorTest,

        activeTexture: activeTexture,
        bindTexture: bindTexture,
        compressedTexImage2D: compressedTexImage2D,
        texImage2D: texImage2D,

        scissor: scissor,
        viewport: viewport,

        reset: reset

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLCapabilities( gl, extensions, parameters ) {

    var maxAnisotropy;

    function getMaxAnisotropy() {

        if ( maxAnisotropy !== undefined ) return maxAnisotropy;

        var extension = extensions.get( 'EXT_texture_filter_anisotropic' );

        if ( extension !== null ) {

            maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );

        } else {

            maxAnisotropy = 0;

        }

        return maxAnisotropy;

    }

    function getMaxPrecision( precision ) {

        if ( precision === 'highp' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
                 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {

                return 'highp';

            }

            precision = 'mediump';

        }

        if ( precision === 'mediump' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
                 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {

                return 'mediump';

            }

        }

        return 'lowp';

    }

    var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
    var maxPrecision = getMaxPrecision( precision );

    if ( maxPrecision !== precision ) {

        console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
        precision = maxPrecision;

    }

    var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' );

    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 maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
    var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
    var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
    var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );

    var vertexTextures = maxVertexTextures > 0;
    var floatFragmentTextures = !! extensions.get( 'OES_texture_float' );
    var floatVertexTextures = vertexTextures && floatFragmentTextures;

    return {

        getMaxAnisotropy: getMaxAnisotropy,
        getMaxPrecision: getMaxPrecision,

        precision: precision,
        logarithmicDepthBuffer: logarithmicDepthBuffer,

        maxTextures: maxTextures,
        maxVertexTextures: maxVertexTextures,
        maxTextureSize: maxTextureSize,
        maxCubemapSize: maxCubemapSize,

        maxAttributes: maxAttributes,
        maxVertexUniforms: maxVertexUniforms,
        maxVaryings: maxVaryings,
        maxFragmentUniforms: maxFragmentUniforms,

        vertexTextures: vertexTextures,
        floatFragmentTextures: floatFragmentTextures,
        floatVertexTextures: floatVertexTextures

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function ArrayCamera( array ) {

    PerspectiveCamera.call( this );

    this.cameras = array || [];

}

ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {

    constructor: ArrayCamera,

    isArrayCamera: true

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebVRManager( renderer ) {

    var scope = this;

    var device = null;
    var frameData = null;

    if ( 'VRFrameData' in window ) {

        frameData = new window.VRFrameData();

    }

    var matrixWorldInverse = new Matrix4();

    var standingMatrix = new Matrix4();
    var standingMatrixInverse = new Matrix4();

    var cameraL = new PerspectiveCamera();
    cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );
    cameraL.layers.enable( 1 );

    var cameraR = new PerspectiveCamera();
    cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );
    cameraR.layers.enable( 2 );

    var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
    cameraVR.layers.enable( 1 );
    cameraVR.layers.enable( 2 );

    //

    var currentSize, currentPixelRatio;

    function onVRDisplayPresentChange() {

        if ( device.isPresenting ) {

            var eyeParameters = device.getEyeParameters( 'left' );
            var renderWidth = eyeParameters.renderWidth;
            var renderHeight = eyeParameters.renderHeight;

            currentPixelRatio = renderer.getPixelRatio();
            currentSize = renderer.getSize();

            renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );

        } else if ( scope.enabled ) {

            renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );

        }

    }

    window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );

    //

    this.enabled = false;
    this.standing = false;

    this.getDevice = function () {

        return device;

    };

    this.setDevice = function ( value ) {

        if ( value !== undefined ) device = value;

    };

    this.getCamera = function ( camera ) {

        if ( device === null ) return camera;

        device.depthNear = camera.near;
        device.depthFar = camera.far;

        device.getFrameData( frameData );

        //

        var pose = frameData.pose;

        if ( pose.position !== null ) {

            camera.position.fromArray( pose.position );

        } else {

            camera.position.set( 0, 0, 0 );

        }

        if ( pose.orientation !== null ) {

            camera.quaternion.fromArray( pose.orientation );

        }

        camera.updateMatrixWorld();

        var stageParameters = device.stageParameters;

        if ( this.standing && stageParameters ) {

            standingMatrix.fromArray( stageParameters.sittingToStandingTransform );
            standingMatrixInverse.getInverse( standingMatrix );

            camera.matrixWorld.multiply( standingMatrix );
            camera.matrixWorldInverse.multiply( standingMatrixInverse );

        }

        if ( device.isPresenting === false ) return camera;

        //

        cameraVR.matrixWorld.copy( camera.matrixWorld );
        cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );

        cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
        cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );

        if ( this.standing && stageParameters ) {

            cameraL.matrixWorldInverse.multiply( standingMatrixInverse );
            cameraR.matrixWorldInverse.multiply( standingMatrixInverse );

        }

        var parent = camera.parent;

        if ( parent !== null ) {

            matrixWorldInverse.getInverse( parent.matrixWorld );

            cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
            cameraR.matrixWorldInverse.multiply( matrixWorldInverse );

        }

        // envMap and Mirror needs camera.matrixWorld

        cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );
        cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );

        cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
        cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );

        // HACK @mrdoob
        // https://github.com/w3c/webvr/issues/203

        cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );

        //

        var layers = device.getLayers();

        if ( layers.length ) {

            var layer = layers[ 0 ];

            if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {

                cameraL.bounds.fromArray( layer.leftBounds );

            }

            if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {

                cameraR.bounds.fromArray( layer.rightBounds );

            }

        }

        return cameraVR;

    };

    this.getStandingMatrix = function () {

        return standingMatrix;

    };

    this.submitFrame = function () {

        if ( device && device.isPresenting ) device.submitFrame();

    };

}

/**
 * @author mrdoob / http://mrdoob.com/
 */

function WebGLExtensions( gl ) {

    var extensions = {};

    return {

        get: function ( name ) {

            if ( extensions[ name ] !== undefined ) {

                return extensions[ name ];

            }

            var extension;

            switch ( name ) {

                case 'WEBGL_depth_texture':
                    extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
                    break;

                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;

                case 'WEBGL_compressed_texture_etc1':
                    extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );
                    break;

                default:
                    extension = gl.getExtension( name );

            }

            if ( extension === null ) {

                console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );

            }

            extensions[ name ] = extension;

            return extension;

        }

    };

}

/**
 * @author tschw
 */

function WebGLClipping() {

    var scope = this,

        globalState = null,
        numGlobalPlanes = 0,
        localClippingEnabled = false,
        renderingShadows = false,

        plane = new Plane(),
        viewNormalMatrix = new Matrix3(),

        uniform = { value: null, needsUpdate: false };

    this.uniform = uniform;
    this.numPlanes = 0;
    this.numIntersection = 0;

    this.init = function( planes, enableLocalClipping, camera ) {

        var enabled =
            planes.length !== 0 ||
            enableLocalClipping ||
            // enable state of previous frame - the clipping code has to
            // run another frame in order to reset the state:
            numGlobalPlanes !== 0 ||
            localClippingEnabled;

        localClippingEnabled = enableLocalClipping;

        globalState = projectPlanes( planes, camera, 0 );
        numGlobalPlanes = planes.length;

        return enabled;

    };

    this.beginShadows = function() {

        renderingShadows = true;
        projectPlanes( null );

    };

    this.endShadows = function() {

        renderingShadows = false;
        resetGlobalState();

    };

    this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {

        if ( ! localClippingEnabled ||
                planes === null || planes.length === 0 ||
                renderingShadows && ! clipShadows ) {
            // there's no local clipping

            if ( renderingShadows ) {
                // there's no global clipping

                projectPlanes( null );

            } else {

                resetGlobalState();
            }

        } else {

            var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
                lGlobal = nGlobal * 4,

                dstArray = cache.clippingState || null;

            uniform.value = dstArray; // ensure unique state

            dstArray = projectPlanes( planes, camera, lGlobal, fromCache );

            for ( var i = 0; i !== lGlobal; ++ i ) {

                dstArray[ i ] = globalState[ i ];

            }

            cache.clippingState = dstArray;
            this.numIntersection = clipIntersection ? this.numPlanes : 0;
            this.numPlanes += nGlobal;

        }


    };

    function resetGlobalState() {

        if ( uniform.value !== globalState ) {

            uniform.value = globalState;
            uniform.needsUpdate = numGlobalPlanes > 0;

        }

        scope.numPlanes = numGlobalPlanes;
        scope.numIntersection = 0;

    }

    function projectPlanes( planes, camera, dstOffset, skipTransform ) {

        var nPlanes = planes !== null ? planes.length : 0,
            dstArray = null;

        if ( nPlanes !== 0 ) {

            dstArray = uniform.value;

            if ( skipTransform !== true || dstArray === null ) {

                var flatSize = dstOffset + nPlanes * 4,
                    viewMatrix = camera.matrixWorldInverse;

                viewNormalMatrix.getNormalMatrix( viewMatrix );

                if ( dstArray === null || dstArray.length < flatSize ) {

                    dstArray = new Float32Array( flatSize );

                }

                for ( var i = 0, i4 = dstOffset;
                                    i !== nPlanes; ++ i, i4 += 4 ) {

                    plane.copy( planes[ i ] ).
                            applyMatrix4( viewMatrix, viewNormalMatrix );

                    plane.normal.toArray( dstArray, i4 );
                    dstArray[ i4 + 3 ] = plane.constant;

                }

            }

            uniform.value = dstArray;
            uniform.needsUpdate = true;

        }

        scope.numPlanes = nPlanes;
        
        return dstArray;

    }

}

// import { Sphere } from '../math/Sphere';
/**
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author szimek / https://github.com/szimek/
 * @author tschw
 */

function WebGLRenderer( parameters ) {

    console.log( 'THREE.WebGLRenderer', REVISION );

    parameters = parameters || {};

    var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
        _context = parameters.context !== undefined ? parameters.context : null,

        _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;

    var lights = [];

    var currentRenderList = null;

    var morphInfluences = new Float32Array( 8 );

    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;

    // user-defined clipping

    this.clippingPlanes = [];
    this.localClippingEnabled = false;

    // physically based shading

    this.gammaFactor = 2.0;    // for backwards compatibility
    this.gammaInput = false;
    this.gammaOutput = false;

    // physical lights

    this.physicallyCorrectLights = false;

    // tone mapping

    this.toneMapping = LinearToneMapping;
    this.toneMappingExposure = 1.0;
    this.toneMappingWhitePoint = 1.0;

    // morphs

    this.maxMorphTargets = 8;
    this.maxMorphNormals = 4;

    // internal properties

    var _this = this,

        // internal state cache

        _currentProgram = null,
        _currentRenderTarget = null,
        _currentFramebuffer = null,
        _currentMaterialId = - 1,
        _currentGeometryProgram = '',

        _currentCamera = null,
        _currentArrayCamera = null,

        _currentScissor = new Vector4(),
        _currentScissorTest = null,

        _currentViewport = new Vector4(),

        //

        _usedTextureUnits = 0,

        //

        _width = _canvas.width,
        _height = _canvas.height,

        _pixelRatio = 1,

        _scissor = new Vector4( 0, 0, _width, _height ),
        _scissorTest = false,

        _viewport = new Vector4( 0, 0, _width, _height ),

        // frustum

        _frustum = new Frustum(),

        // clipping

        _clipping = new WebGLClipping(),
        _clippingEnabled = false,
        _localClippingEnabled = false,

        // camera matrices cache

        _projScreenMatrix = new Matrix4(),

        _vector3 = new Vector3(),
        _matrix4 = new Matrix4(),
        _matrix42 = new Matrix4(),

        // light arrays cache

        _lights = {

            hash: '',

            ambient: [ 0, 0, 0 ],
            directional: [],
            directionalShadowMap: [],
            directionalShadowMatrix: [],
            spot: [],
            spotShadowMap: [],
            spotShadowMatrix: [],
            rectArea: [],
            point: [],
            pointShadowMap: [],
            pointShadowMatrix: [],
            hemi: [],

            shadows: []

        },

        // info

        _infoMemory = {
            geometries: 0,
            textures: 0
        },

        _infoRender = {

            frame: 0,
            calls: 0,
            vertices: 0,
            faces: 0,
            points: 0

        };

    this.info = {

        render: _infoRender,
        memory: _infoMemory,
        programs: null

    };


    // initialize

    var _gl;

    try {

        var contextAttributes = {
            alpha: _alpha,
            depth: _depth,
            stencil: _stencil,
            antialias: _antialias,
            premultipliedAlpha: _premultipliedAlpha,
            preserveDrawingBuffer: _preserveDrawingBuffer
        };

        _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );

        if ( _gl === null ) {

            if ( _canvas.getContext( 'webgl' ) !== null ) {

                throw 'Error creating WebGL context with your selected attributes.';

            } else {

                throw 'Error creating WebGL context.';

            }

        }

        // Some experimental-webgl implementations do not have getShaderPrecisionFormat

        if ( _gl.getShaderPrecisionFormat === undefined ) {

            _gl.getShaderPrecisionFormat = function () {

                return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };

            };

        }

        _canvas.addEventListener( 'webglcontextlost', onContextLost, false );

    } catch ( error ) {

        console.error( 'THREE.WebGLRenderer: ' + error );

    }

    var extensions = new WebGLExtensions( _gl );

    extensions.get( 'WEBGL_depth_texture' );
    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' );
    extensions.get( 'ANGLE_instanced_arrays' );

    if ( extensions.get( 'OES_element_index_uint' ) ) {

        BufferGeometry.MaxIndex = 4294967296;

    }

    var capabilities = new WebGLCapabilities( _gl, extensions, parameters );

    var state = new WebGLState( _gl, extensions, paramThreeToGL );

    var properties = new WebGLProperties();
    var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, _infoMemory );
    var attributes = new WebGLAttributes( _gl );
    var geometries = new WebGLGeometries( _gl, attributes, _infoMemory );
    var objects = new WebGLObjects( _gl, geometries, _infoRender );
    var programCache = new WebGLPrograms( this, capabilities );
    var lightCache = new WebGLLights();
    var renderLists = new WebGLRenderLists();

    var background = new WebGLBackground( this, state, objects, _premultipliedAlpha );
    var vr = new WebVRManager( this );

    this.info.programs = programCache.programs;

    var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
    var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );

    //

    function getTargetPixelRatio() {

        return _currentRenderTarget === null ? _pixelRatio : 1;

    }

    function setDefaultGLState() {

        state.init();

        state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
        state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );

    }

    function resetGLState() {

        _currentProgram = null;
        _currentCamera = null;

        _currentGeometryProgram = '';
        _currentMaterialId = - 1;

        state.reset();

    }

    setDefaultGLState();

    this.context = _gl;
    this.capabilities = capabilities;
    this.extensions = extensions;
    this.properties = properties;
    this.renderLists = renderLists;
    this.state = state;
    this.vr = vr;

    // shadow map

    var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities );

    this.shadowMap = shadowMap;


    // Plugins

    var spritePlugin = new SpritePlugin( this, sprites );
    var lensFlarePlugin = new LensFlarePlugin( this, lensFlares );

    // API

    this.getContext = function () {

        return _gl;

    };

    this.getContextAttributes = function () {

        return _gl.getContextAttributes();

    };

    this.forceContextLoss = function () {

        var extension = extensions.get( 'WEBGL_lose_context' );
        if ( extension ) extension.loseContext();

    };

    this.getMaxAnisotropy = function () {

        return capabilities.getMaxAnisotropy();

    };

    this.getPrecision = function () {

        return capabilities.precision;

    };

    this.getPixelRatio = function () {

        return _pixelRatio;

    };

    this.setPixelRatio = function ( value ) {

        if ( value === undefined ) return;

        _pixelRatio = value;

        this.setSize( _width, _height, false );

    };

    this.getSize = function () {

        return {
            width: _width,
            height: _height
        };

    };

    this.setSize = function ( width, height, updateStyle ) {

        var device = vr.getDevice();

        if ( device && device.isPresenting ) {

            console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
            return;

        }

        _width = width;
        _height = height;

        _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.getDrawingBufferSize = function () {

        return {
            width: _width * _pixelRatio,
            height: _height * _pixelRatio
        };

    };

    this.setDrawingBufferSize = function ( width, height, pixelRatio ) {

        _width = width;
        _height = height;

        _pixelRatio = pixelRatio;

        _canvas.width = width * pixelRatio;
        _canvas.height = height * pixelRatio;

        this.setViewport( 0, 0, width, height );

    };

    this.setViewport = function ( x, y, width, height ) {

        _viewport.set( x, _height - y - height, width, height );
        state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );

    };

    this.setScissor = function ( x, y, width, height ) {

        _scissor.set( x, _height - y - height, width, height );
        state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );

    };

    this.setScissorTest = function ( boolean ) {

        state.setScissorTest( _scissorTest = boolean );

    };

    // Clearing

    this.getClearColor = background.getClearColor;
    this.setClearColor = background.setClearColor;
    this.getClearAlpha = background.getClearAlpha;
    this.setClearAlpha = background.setClearAlpha;

    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 () {

        this.clear( true, false, false );

    };

    this.clearDepth = function () {

        this.clear( false, true, false );

    };

    this.clearStencil = function () {

        this.clear( false, false, true );

    };

    this.clearTarget = function ( renderTarget, color, depth, stencil ) {

        this.setRenderTarget( renderTarget );
        this.clear( color, depth, stencil );

    };

    // Reset

    this.resetGLState = resetGLState;

    this.dispose = function () {

        _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );

        renderLists.dispose();

    };

    // Events

    function onContextLost( event ) {

        event.preventDefault();

        resetGLState();
        setDefaultGLState();

        properties.clear();
        objects.clear();

    }

    function onMaterialDispose( event ) {

        var material = event.target;

        material.removeEventListener( 'dispose', onMaterialDispose );

        deallocateMaterial( material );

    }

    // Buffer deallocation

    function deallocateMaterial( material ) {

        releaseMaterialProgramReference( material );

        properties.remove( material );

    }


    function releaseMaterialProgramReference( material ) {

        var programInfo = properties.get( material ).program;

        material.program = undefined;

        if ( programInfo !== undefined ) {

            programCache.releaseProgram( programInfo );

        }

    }

    // Buffer rendering

    function renderObjectImmediate( object, program, material ) {

        object.render( function ( object ) {

            _this.renderBufferImmediate( object, program, material );

        } );

    }

    this.renderBufferImmediate = function ( object, program, material ) {

        state.initAttributes();

        var buffers = properties.get( object );

        if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
        if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
        if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
        if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();

        var programAttributes = program.getAttributes();

        if ( object.hasPositions ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );

            state.enableAttribute( programAttributes.position );
            _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasNormals ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );

            if ( ! material.isMeshPhongMaterial &&
                ! material.isMeshStandardMaterial &&
                ! material.isMeshNormalMaterial &&
                material.shading === FlatShading ) {

                for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {

                    var array = object.normalArray;

                    var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
                    var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
                    var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;

                    array[ i + 0 ] = nx;
                    array[ i + 1 ] = ny;
                    array[ i + 2 ] = nz;

                    array[ i + 3 ] = nx;
                    array[ i + 4 ] = ny;
                    array[ i + 5 ] = nz;

                    array[ i + 6 ] = nx;
                    array[ i + 7 ] = ny;
                    array[ i + 8 ] = nz;

                }

            }

            _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );

            state.enableAttribute( programAttributes.normal );

            _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasUvs && material.map ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );

            state.enableAttribute( programAttributes.uv );

            _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasColors && material.vertexColors !== NoColors ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );

            state.enableAttribute( programAttributes.color );

            _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );

        }

        state.disableUnusedAttributes();

        _gl.drawArrays( _gl.TRIANGLES, 0, object.count );

        object.count = 0;

    };

    function absNumericalSort( a, b ) {

        return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] );

    }

    this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {

        state.setMaterial( material );

        var program = setProgram( camera, fog, material, object );
        var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true );

        var updateBuffers = false;

        if ( geometryProgram !== _currentGeometryProgram ) {

            _currentGeometryProgram = geometryProgram;
            updateBuffers = true;

        }

        // morph targets

        var morphTargetInfluences = object.morphTargetInfluences;

        if ( morphTargetInfluences !== undefined ) {

            // TODO Remove allocations

            var activeInfluences = [];

            for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) {

                var influence = morphTargetInfluences[ i ];
                activeInfluences.push( [ influence, i ] );

            }

            activeInfluences.sort( absNumericalSort );

            if ( activeInfluences.length > 8 ) {

                activeInfluences.length = 8;

            }

            var morphAttributes = geometry.morphAttributes;

            for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) {

                var influence = activeInfluences[ i ];
                morphInfluences[ i ] = influence[ 0 ];

                if ( influence[ 0 ] !== 0 ) {

                    var index = influence[ 1 ];

                    if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] );
                    if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] );

                } else {

                    if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i );
                    if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i );

                }

            }

            for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) {

                morphInfluences[ i ] = 0.0;

            }

            program.getUniforms().setValue( _gl, 'morphTargetInfluences', morphInfluences );

            updateBuffers = true;

        }

        //

        var index = geometry.index;
        var position = geometry.attributes.position;
        var rangeFactor = 1;

        if ( material.wireframe === true ) {

            index = geometries.getWireframeAttribute( geometry );
            rangeFactor = 2;

        }

        var attribute;
        var renderer = bufferRenderer;

        if ( index !== null ) {

            attribute = attributes.get( index );

            renderer = indexedBufferRenderer;
            renderer.setIndex( attribute );

        }

        if ( updateBuffers ) {

            setupVertexAttributes( material, program, geometry );

            if ( index !== null ) {

                _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer );

            }

        }

        //

        var dataCount = 0;

        if ( index !== null ) {

            dataCount = index.count;

        } else if ( position !== undefined ) {

            dataCount = position.count;

        }

        var rangeStart = geometry.drawRange.start * rangeFactor;
        var rangeCount = geometry.drawRange.count * rangeFactor;

        var groupStart = group !== null ? group.start * rangeFactor : 0;
        var groupCount = group !== null ? group.count * rangeFactor : Infinity;

        var drawStart = Math.max( rangeStart, groupStart );
        var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;

        var drawCount = Math.max( 0, drawEnd - drawStart + 1 );

        if ( drawCount === 0 ) return;

        //

        if ( object.isMesh ) {

            if ( material.wireframe === true ) {

                state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
                renderer.setMode( _gl.LINES );

            } else {

                switch ( object.drawMode ) {

                    case TrianglesDrawMode:
                        renderer.setMode( _gl.TRIANGLES );
                        break;

                    case TriangleStripDrawMode:
                        renderer.setMode( _gl.TRIANGLE_STRIP );
                        break;

                    case TriangleFanDrawMode:
                        renderer.setMode( _gl.TRIANGLE_FAN );
                        break;

                }

            }


        } else if ( object.isLine ) {

            var lineWidth = material.linewidth;

            if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material

            state.setLineWidth( lineWidth * getTargetPixelRatio() );

            if ( object.isLineSegments ) {

                renderer.setMode( _gl.LINES );

            } else if ( object.isLineLoop ) {

                renderer.setMode( _gl.LINE_LOOP );

            } else {

                renderer.setMode( _gl.LINE_STRIP );

            }

        } else if ( object.isPoints ) {

            renderer.setMode( _gl.POINTS );

        }

        if ( geometry && geometry.isInstancedBufferGeometry ) {

            if ( geometry.maxInstancedCount > 0 ) {

                renderer.renderInstances( geometry, drawStart, drawCount );

            }

        } else {

            renderer.render( drawStart, drawCount );

        }

    };

    function setupVertexAttributes( material, program, geometry, startIndex ) {

        if ( geometry && geometry.isInstancedBufferGeometry ) {

            if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {

                console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
                return;

            }

        }

        if ( startIndex === undefined ) startIndex = 0;

        state.initAttributes();

        var geometryAttributes = geometry.attributes;

        var programAttributes = program.getAttributes();

        var materialDefaultAttributeValues = material.defaultAttributeValues;

        for ( var name in programAttributes ) {

            var programAttribute = programAttributes[ name ];

            if ( programAttribute >= 0 ) {

                var geometryAttribute = geometryAttributes[ name ];

                if ( geometryAttribute !== undefined ) {

                    var normalized = geometryAttribute.normalized;
                    var size = geometryAttribute.itemSize;

                    var attribute = attributes.get( geometryAttribute );

                    var buffer = attribute.buffer;
                    var type = attribute.type;
                    var bytesPerElement = attribute.bytesPerElement;

                    if ( geometryAttribute.isInterleavedBufferAttribute ) {

                        var data = geometryAttribute.data;
                        var stride = data.stride;
                        var offset = geometryAttribute.offset;

                        if ( data && data.isInstancedInterleavedBuffer ) {

                            state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );

                            if ( geometry.maxInstancedCount === undefined ) {

                                geometry.maxInstancedCount = data.meshPerAttribute * data.count;

                            }

                        } else {

                            state.enableAttribute( programAttribute );

                        }

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
                        _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );

                    } else {

                        if ( geometryAttribute.isInstancedBufferAttribute ) {

                            state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );

                            if ( geometry.maxInstancedCount === undefined ) {

                                geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;

                            }

                        } else {

                            state.enableAttribute( programAttribute );

                        }

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
                        _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );

                    }

                } else if ( materialDefaultAttributeValues !== undefined ) {

                    var value = materialDefaultAttributeValues[ name ];

                    if ( value !== undefined ) {

                        switch ( value.length ) {

                            case 2:
                                _gl.vertexAttrib2fv( programAttribute, value );
                                break;

                            case 3:
                                _gl.vertexAttrib3fv( programAttribute, value );
                                break;

                            case 4:
                                _gl.vertexAttrib4fv( programAttribute, value );
                                break;

                            default:
                                _gl.vertexAttrib1fv( programAttribute, value );

                        }

                    }

                }

            }

        }

        state.disableUnusedAttributes();

    }

    // Compile

    this.compile = function ( scene, camera ) {

        lights = [];

        scene.traverse( function ( object ) {

            if ( object.isLight ) {

                lights.push( object );

            }

        } );

        setupLights( lights, camera );

        scene.traverse( function ( object ) {

            if ( object.material ) {

                if ( Array.isArray( object.material ) ) {

                    for ( var i = 0; i < object.material.length; i ++ ) {

                        initMaterial( object.material[ i ], scene.fog, object );

                    }

                } else {

                    initMaterial( object.material, scene.fog, object );

                }

            }

        } );

    };

    // Rendering

    this.animate = function ( callback ) {

        function onFrame() {

            callback();

            ( vr.getDevice() || window ).requestAnimationFrame( onFrame );

        }

        ( vr.getDevice() || window ).requestAnimationFrame( onFrame );

    };

    this.render = function ( scene, camera, renderTarget, forceClear ) {

        if ( ! ( camera && camera.isCamera ) ) {

            console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
            return;

        }

        // reset caching for this frame

        _currentGeometryProgram = '';
        _currentMaterialId = - 1;
        _currentCamera = null;

        // update scene graph

        if ( scene.autoUpdate === true ) scene.updateMatrixWorld();

        // update camera matrices and frustum

        if ( camera.parent === null ) camera.updateMatrixWorld();

        if ( vr.enabled ) {

            camera = vr.getCamera( camera );

        }

        _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
        _frustum.setFromMatrix( _projScreenMatrix );

        lights.length = 0;
        sprites.length = 0;
        lensFlares.length = 0;

        _localClippingEnabled = this.localClippingEnabled;
        _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );

        currentRenderList = renderLists.get( scene, camera );
        currentRenderList.init();

        projectObject( scene, camera, _this.sortObjects );

        currentRenderList.finish();

        if ( _this.sortObjects === true ) {

            currentRenderList.sort();

        }

        //

        if ( _clippingEnabled ) _clipping.beginShadows();

        setupShadows( lights );

        shadowMap.render( scene, camera );

        setupLights( lights, camera );

        if ( _clippingEnabled ) _clipping.endShadows();

        //

        _infoRender.frame ++;
        _infoRender.calls = 0;
        _infoRender.vertices = 0;
        _infoRender.faces = 0;
        _infoRender.points = 0;

        if ( renderTarget === undefined ) {

            renderTarget = null;

        }

        this.setRenderTarget( renderTarget );

        //

        background.render( scene, camera, forceClear );

        // render scene

        var opaqueObjects = currentRenderList.opaque;
        var transparentObjects = currentRenderList.transparent;

        if ( scene.overrideMaterial ) {

            var overrideMaterial = scene.overrideMaterial;

            if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial );
            if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );

        } else {

            // opaque pass (front-to-back order)

            if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );

            // transparent pass (back-to-front order)

            if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );

        }

        // custom render plugins (post pass)

        spritePlugin.render( scene, camera );
        lensFlarePlugin.render( scene, camera, _currentViewport );

        // Generate mipmap if we're using any kind of mipmap filtering

        if ( renderTarget ) {

            textures.updateRenderTargetMipmap( renderTarget );

        }

        // Ensure depth buffer writing is enabled so it can be cleared on next render

        state.buffers.depth.setTest( true );
        state.buffers.depth.setMask( true );
        state.buffers.color.setMask( true );

        if ( camera.isArrayCamera ) {

            _this.setScissorTest( false );

        }

        if ( vr.enabled ) {

            vr.submitFrame();

        }

        // _gl.finish();

    };

    /*
    // TODO Duplicated code (Frustum)

    var _sphere = new Sphere();

    function isObjectViewable( object ) {

        var geometry = object.geometry;

        if ( geometry.boundingSphere === null )
            geometry.computeBoundingSphere();

        _sphere.copy( geometry.boundingSphere ).
        applyMatrix4( object.matrixWorld );

        return isSphereViewable( _sphere );

    }

    function isSpriteViewable( sprite ) {

        _sphere.center.set( 0, 0, 0 );
        _sphere.radius = 0.7071067811865476;
        _sphere.applyMatrix4( sprite.matrixWorld );

        return isSphereViewable( _sphere );

    }

    function isSphereViewable( sphere ) {

        if ( ! _frustum.intersectsSphere( sphere ) ) return false;

        var numPlanes = _clipping.numPlanes;

        if ( numPlanes === 0 ) return true;

        var planes = _this.clippingPlanes,

            center = sphere.center,
            negRad = - sphere.radius,
            i = 0;

        do {

            // out when deeper than radius in the negative halfspace
            if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;

        } while ( ++ i !== numPlanes );

        return true;

    }
    */

    function projectObject( object, camera, sortObjects ) {

        if ( ! object.visible ) return;

        var visible = object.layers.test( camera.layers );

        if ( visible ) {

            if ( object.isLight ) {

                lights.push( object );

            } else if ( object.isSprite ) {

                if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {

                    sprites.push( object );

                }

            } else if ( object.isLensFlare ) {

                lensFlares.push( object );

            } else if ( object.isImmediateRenderObject ) {

                if ( sortObjects ) {

                    _vector3.setFromMatrixPosition( object.matrixWorld )
                        .applyMatrix4( _projScreenMatrix );

                }

                currentRenderList.push( object, null, object.material, _vector3.z, null );

            } else if ( object.isMesh || object.isLine || object.isPoints ) {

                if ( object.isSkinnedMesh ) {

                    object.skeleton.update();

                }

                if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {

                    if ( sortObjects ) {

                        _vector3.setFromMatrixPosition( object.matrixWorld )
                            .applyMatrix4( _projScreenMatrix );

                    }

                    var geometry = objects.update( object );
                    var material = object.material;

                    if ( Array.isArray( material ) ) {

                        var groups = geometry.groups;

                        for ( var i = 0, l = groups.length; i < l; i ++ ) {

                            var group = groups[ i ];
                            var groupMaterial = material[ group.materialIndex ];

                            if ( groupMaterial && groupMaterial.visible ) {

                                currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group );

                            }

                        }

                    } else if ( material.visible ) {

                        currentRenderList.push( object, geometry, material, _vector3.z, null );

                    }

                }

            }

        }

        var children = object.children;

        for ( var i = 0, l = children.length; i < l; i ++ ) {

            projectObject( children[ i ], camera, sortObjects );

        }

    }

    function renderObjects( renderList, scene, camera, overrideMaterial ) {

        for ( var i = 0, l = renderList.length; i < l; i ++ ) {

            var renderItem = renderList[ i ];

            var object = renderItem.object;
            var geometry = renderItem.geometry;
            var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
            var group = renderItem.group;

            if ( camera.isArrayCamera ) {

                _currentArrayCamera = camera;

                var cameras = camera.cameras;

                for ( var j = 0, jl = cameras.length; j < jl; j ++ ) {

                    var camera2 = cameras[ j ];

                    if ( object.layers.test( camera2.layers ) ) {

                        var bounds = camera2.bounds;

                        var x = bounds.x * _width;
                        var y = bounds.y * _height;
                        var width = bounds.z * _width;
                        var height = bounds.w * _height;

                        _this.setViewport( x, y, width, height );
                        _this.setScissor( x, y, width, height );
                        _this.setScissorTest( true );

                        renderObject( object, scene, camera2, geometry, material, group );

                    }

                }

            } else {

                _currentArrayCamera = null;

                renderObject( object, scene, camera, geometry, material, group );

            }

        }

    }

    function renderObject( object, scene, camera, geometry, material, group ) {

        object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
        object.normalMatrix.getNormalMatrix( object.modelViewMatrix );

        object.onBeforeRender( _this, scene, camera, geometry, material, group );

        if ( object.isImmediateRenderObject ) {

            state.setMaterial( material );

            var program = setProgram( camera, scene.fog, material, object );

            _currentGeometryProgram = '';

            renderObjectImmediate( object, program, material );

        } else {

            _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );

        }

        object.onAfterRender( _this, scene, camera, geometry, material, group );

    }

    function initMaterial( material, fog, object ) {

        var materialProperties = properties.get( material );

        var parameters = programCache.getParameters(
            material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object );

        var code = programCache.getProgramCode( material, parameters );

        var program = materialProperties.program;
        var programChange = true;

        if ( program === undefined ) {

            // new material
            material.addEventListener( 'dispose', onMaterialDispose );

        } else if ( program.code !== code ) {

            // changed glsl or parameters
            releaseMaterialProgramReference( material );

        } else if ( parameters.shaderID !== undefined ) {

            // same glsl and uniform list
            return;

        } else {

            // only rebuild uniform list
            programChange = false;

        }

        if ( programChange ) {

            if ( parameters.shaderID ) {

                var shader = ShaderLib[ parameters.shaderID ];

                materialProperties.shader = {
                    name: material.type,
                    uniforms: UniformsUtils.clone( shader.uniforms ),
                    vertexShader: shader.vertexShader,
                    fragmentShader: shader.fragmentShader
                };

            } else {

                materialProperties.shader = {
                    name: material.type,
                    uniforms: material.uniforms,
                    vertexShader: material.vertexShader,
                    fragmentShader: material.fragmentShader
                };

            }

            material.onBeforeCompile( materialProperties.shader );

            program = programCache.acquireProgram( material, materialProperties.shader, parameters, code );

            materialProperties.program = program;
            material.program = program;

        }

        var programAttributes = program.getAttributes();

        if ( material.morphTargets ) {

            material.numSupportedMorphTargets = 0;

            for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {

                if ( programAttributes[ 'morphTarget' + i ] >= 0 ) {

                    material.numSupportedMorphTargets ++;

                }

            }

        }

        if ( material.morphNormals ) {

            material.numSupportedMorphNormals = 0;

            for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {

                if ( programAttributes[ 'morphNormal' + i ] >= 0 ) {

                    material.numSupportedMorphNormals ++;

                }

            }

        }

        var uniforms = materialProperties.shader.uniforms;

        if ( ! material.isShaderMaterial &&
            ! material.isRawShaderMaterial ||
            material.clipping === true ) {

            materialProperties.numClippingPlanes = _clipping.numPlanes;
            materialProperties.numIntersection = _clipping.numIntersection;
            uniforms.clippingPlanes = _clipping.uniform;

        }

        materialProperties.fog = fog;

        // store the light setup it was created for

        materialProperties.lightsHash = _lights.hash;

        if ( material.lights ) {

            // wire up the material to this renderer's lighting state

            uniforms.ambientLightColor.value = _lights.ambient;
            uniforms.directionalLights.value = _lights.directional;
            uniforms.spotLights.value = _lights.spot;
            uniforms.rectAreaLights.value = _lights.rectArea;
            uniforms.pointLights.value = _lights.point;
            uniforms.hemisphereLights.value = _lights.hemi;

            uniforms.directionalShadowMap.value = _lights.directionalShadowMap;
            uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix;
            uniforms.spotShadowMap.value = _lights.spotShadowMap;
            uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix;
            uniforms.pointShadowMap.value = _lights.pointShadowMap;
            uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix;
            // TODO (abelnation): add area lights shadow info to uniforms

        }

        var progUniforms = materialProperties.program.getUniforms(),
            uniformsList =
                WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );

        materialProperties.uniformsList = uniformsList;

    }

    function setProgram( camera, fog, material, object ) {

        _usedTextureUnits = 0;

        var materialProperties = properties.get( material );

        if ( _clippingEnabled ) {

            if ( _localClippingEnabled || camera !== _currentCamera ) {

                var useCache =
                    camera === _currentCamera &&
                    material.id === _currentMaterialId;

                // we might want to call this function with some ClippingGroup
                // object instead of the material, once it becomes feasible
                // (#8465, #8379)
                _clipping.setState(
                    material.clippingPlanes, material.clipIntersection, material.clipShadows,
                    camera, materialProperties, useCache );

            }

        }

        if ( material.needsUpdate === false ) {

            if ( materialProperties.program === undefined ) {

                material.needsUpdate = true;

            } else if ( material.fog && materialProperties.fog !== fog ) {

                material.needsUpdate = true;

            } else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) {

                material.needsUpdate = true;

            } else if ( materialProperties.numClippingPlanes !== undefined &&
                ( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
                materialProperties.numIntersection !== _clipping.numIntersection ) ) {

                material.needsUpdate = true;

            }

        }

        if ( material.needsUpdate ) {

            initMaterial( material, fog, object );
            material.needsUpdate = false;

        }

        var refreshProgram = false;
        var refreshMaterial = false;
        var refreshLights = false;

        var program = materialProperties.program,
            p_uniforms = program.getUniforms(),
            m_uniforms = materialProperties.shader.uniforms;

        if ( program.id !== _currentProgram ) {

            _gl.useProgram( program.program );
            _currentProgram = program.id;

            refreshProgram = true;
            refreshMaterial = true;
            refreshLights = true;

        }

        if ( material.id !== _currentMaterialId ) {

            _currentMaterialId = material.id;

            refreshMaterial = true;

        }

        if ( refreshProgram || camera !== _currentCamera ) {

            p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );

            if ( capabilities.logarithmicDepthBuffer ) {

                p_uniforms.setValue( _gl, 'logDepthBufFC',
                    2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );

            }

            // Avoid unneeded uniform updates per ArrayCamera's sub-camera

            if ( _currentCamera !== ( _currentArrayCamera || camera ) ) {

                _currentCamera = ( _currentArrayCamera || camera );

                // lighting uniforms depend on the camera so enforce an update
                // now, in case this material supports lights - or later, when
                // the next material that does gets activated:

                refreshMaterial = true;        // set to true on material change
                refreshLights = true;        // remains set until update done

            }

            // load material specific uniforms
            // (shader material also gets them for the sake of genericity)

            if ( material.isShaderMaterial ||
                material.isMeshPhongMaterial ||
                material.isMeshStandardMaterial ||
                material.envMap ) {

                var uCamPos = p_uniforms.map.cameraPosition;

                if ( uCamPos !== undefined ) {

                    uCamPos.setValue( _gl,
                        _vector3.setFromMatrixPosition( camera.matrixWorld ) );

                }

            }

            if ( material.isMeshPhongMaterial ||
                material.isMeshLambertMaterial ||
                material.isMeshBasicMaterial ||
                material.isMeshStandardMaterial ||
                material.isShaderMaterial ||
                material.skinning ) {

                p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );

            }

        }

        // 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 ) {

            p_uniforms.setOptional( _gl, object, 'bindMatrix' );
            p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );

            var skeleton = object.skeleton;

            if ( skeleton ) {

                var bones = skeleton.bones;

                if ( capabilities.floatVertexTextures ) {

                    if ( skeleton.boneTexture === undefined ) {

                        // layout (1 matrix = 4 pixels)
                        //      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
                        //  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
                        //       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
                        //       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
                        //       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)


                        var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
                        size = _Math.nextPowerOfTwo( Math.ceil( size ) );
                        size = Math.max( size, 4 );

                        var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
                        boneMatrices.set( skeleton.boneMatrices ); // copy current values

                        var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );

                        skeleton.boneMatrices = boneMatrices;
                        skeleton.boneTexture = boneTexture;
                        skeleton.boneTextureSize = size;

                    }

                    p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture );
                    p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );

                } else {

                    p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );

                }

            }

        }

        if ( refreshMaterial ) {

            p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
            p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );

            if ( material.lights ) {

                // the current material requires lighting info

                // note: all lighting uniforms are always set correctly
                // they simply reference the renderer's state for their
                // values
                //
                // use the current material's .needsUpdate flags to set
                // the GL state when required

                markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );

            }

            // refresh uniforms common to several materials

            if ( fog && material.fog ) {

                refreshUniformsFog( m_uniforms, fog );

            }

            if ( material.isMeshBasicMaterial ||
                material.isMeshLambertMaterial ||
                material.isMeshPhongMaterial ||
                material.isMeshStandardMaterial ||
                material.isMeshNormalMaterial ||
                material.isMeshDepthMaterial ) {

                refreshUniformsCommon( m_uniforms, material );

            }

            // refresh single material specific uniforms

            if ( material.isLineBasicMaterial ) {

                refreshUniformsLine( m_uniforms, material );

            } else if ( material.isLineDashedMaterial ) {

                refreshUniformsLine( m_uniforms, material );
                refreshUniformsDash( m_uniforms, material );

            } else if ( material.isPointsMaterial ) {

                refreshUniformsPoints( m_uniforms, material );

            } else if ( material.isMeshLambertMaterial ) {

                refreshUniformsLambert( m_uniforms, material );

            } else if ( material.isMeshToonMaterial ) {

                refreshUniformsToon( m_uniforms, material );

            } else if ( material.isMeshPhongMaterial ) {

                refreshUniformsPhong( m_uniforms, material );

            } else if ( material.isMeshPhysicalMaterial ) {

                refreshUniformsPhysical( m_uniforms, material );

            } else if ( material.isMeshStandardMaterial ) {

                refreshUniformsStandard( m_uniforms, material );

            } else if ( material.isMeshDepthMaterial ) {

                if ( material.displacementMap ) {

                    m_uniforms.displacementMap.value = material.displacementMap;
                    m_uniforms.displacementScale.value = material.displacementScale;
                    m_uniforms.displacementBias.value = material.displacementBias;

                }

            } else if ( material.isMeshNormalMaterial ) {

                refreshUniformsNormal( m_uniforms, material );

            }

            // RectAreaLight Texture
            // TODO (mrdoob): Find a nicer implementation

            if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE;
            if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE;

            WebGLUniforms.upload(
                _gl, materialProperties.uniformsList, m_uniforms, _this );

        }


        // common matrices

        p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
        p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
        p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );

        return program;

    }

    // Uniforms (refresh uniforms objects)

    function refreshUniformsCommon( uniforms, material ) {

        uniforms.opacity.value = material.opacity;

        uniforms.diffuse.value = material.color;

        if ( material.emissive ) {

            uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );

        }

        uniforms.map.value = material.map;
        uniforms.specularMap.value = material.specularMap;
        uniforms.alphaMap.value = material.alphaMap;

        if ( material.lightMap ) {

            uniforms.lightMap.value = material.lightMap;
            uniforms.lightMapIntensity.value = material.lightMapIntensity;

        }

        if ( material.aoMap ) {

            uniforms.aoMap.value = material.aoMap;
            uniforms.aoMapIntensity.value = material.aoMapIntensity;

        }

        // uv repeat and offset setting priorities
        // 1. color map
        // 2. specular map
        // 3. normal map
        // 4. bump map
        // 5. alpha map
        // 6. emissive map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.displacementMap ) {

            uvScaleMap = material.displacementMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        } else if ( material.roughnessMap ) {

            uvScaleMap = material.roughnessMap;

        } else if ( material.metalnessMap ) {

            uvScaleMap = material.metalnessMap;

        } else if ( material.alphaMap ) {

            uvScaleMap = material.alphaMap;

        } else if ( material.emissiveMap ) {

            uvScaleMap = material.emissiveMap;

        }

        if ( uvScaleMap !== undefined ) {

            // backwards compatibility
            if ( uvScaleMap.isWebGLRenderTarget ) {

                uvScaleMap = uvScaleMap.texture;

            }

            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;

        // don't flip CubeTexture envMaps, flip everything else:
        //  WebGLRenderTargetCube will be flipped for backwards compatibility
        //  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
        // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
        uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 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 refreshUniformsPoints( uniforms, material ) {

        uniforms.diffuse.value = material.color;
        uniforms.opacity.value = material.opacity;
        uniforms.size.value = material.size * _pixelRatio;
        uniforms.scale.value = _height * 0.5;

        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.isFog ) {

            uniforms.fogNear.value = fog.near;
            uniforms.fogFar.value = fog.far;

        } else if ( fog.isFogExp2 ) {

            uniforms.fogDensity.value = fog.density;

        }

    }

    function refreshUniformsLambert( uniforms, material ) {

        if ( material.emissiveMap ) {

            uniforms.emissiveMap.value = material.emissiveMap;

        }

    }

    function refreshUniformsPhong( uniforms, material ) {

        uniforms.specular.value = material.specular;
        uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )

        if ( material.emissiveMap ) {

            uniforms.emissiveMap.value = material.emissiveMap;

        }

        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 );

        }

        if ( material.displacementMap ) {

            uniforms.displacementMap.value = material.displacementMap;
            uniforms.displacementScale.value = material.displacementScale;
            uniforms.displacementBias.value = material.displacementBias;

        }

    }

    function refreshUniformsToon( uniforms, material ) {

        refreshUniformsPhong( uniforms, material );

        if ( material.gradientMap ) {

            uniforms.gradientMap.value = material.gradientMap;

        }

    }

    function refreshUniformsStandard( uniforms, material ) {

        uniforms.roughness.value = material.roughness;
        uniforms.metalness.value = material.metalness;

        if ( material.roughnessMap ) {

            uniforms.roughnessMap.value = material.roughnessMap;

        }

        if ( material.metalnessMap ) {

            uniforms.metalnessMap.value = material.metalnessMap;

        }

        if ( material.emissiveMap ) {

            uniforms.emissiveMap.value = material.emissiveMap;

        }

        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 );

        }

        if ( material.displacementMap ) {

            uniforms.displacementMap.value = material.displacementMap;
            uniforms.displacementScale.value = material.displacementScale;
            uniforms.displacementBias.value = material.displacementBias;

        }

        if ( material.envMap ) {

            //uniforms.envMap.value = material.envMap; // part of uniforms common
            uniforms.envMapIntensity.value = material.envMapIntensity;

        }

    }

    function refreshUniformsPhysical( uniforms, material ) {

        uniforms.clearCoat.value = material.clearCoat;
        uniforms.clearCoatRoughness.value = material.clearCoatRoughness;

        refreshUniformsStandard( uniforms, material );

    }

    function refreshUniformsNormal( uniforms, material ) {

        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 );

        }

        if ( material.displacementMap ) {

            uniforms.displacementMap.value = material.displacementMap;
            uniforms.displacementScale.value = material.displacementScale;
            uniforms.displacementBias.value = material.displacementBias;

        }

    }

    // 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.directionalLights.needsUpdate = value;
        uniforms.pointLights.needsUpdate = value;
        uniforms.spotLights.needsUpdate = value;
        uniforms.rectAreaLights.needsUpdate = value;
        uniforms.hemisphereLights.needsUpdate = value;

    }

    // Lighting

    function setupShadows( lights ) {

        var lightShadowsLength = 0;

        for ( var i = 0, l = lights.length; i < l; i ++ ) {

            var light = lights[ i ];

            if ( light.castShadow ) {

                _lights.shadows[ lightShadowsLength ] = light;
                lightShadowsLength ++;

            }

        }

        _lights.shadows.length = lightShadowsLength;

    }

    function setupLights( lights, camera ) {

        var l, ll, light, shadow,
            r = 0, g = 0, b = 0,
            color,
            intensity,
            distance,
            shadowMap,

            viewMatrix = camera.matrixWorldInverse,

            directionalLength = 0,
            pointLength = 0,
            spotLength = 0,
            rectAreaLength = 0,
            hemiLength = 0;

        for ( l = 0, ll = lights.length; l < ll; l ++ ) {

            light = lights[ l ];

            color = light.color;
            intensity = light.intensity;
            distance = light.distance;

            shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;

            if ( light.isAmbientLight ) {

                r += color.r * intensity;
                g += color.g * intensity;
                b += color.b * intensity;

            } else if ( light.isDirectionalLight ) {

                var uniforms = lightCache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                _vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( _vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                uniforms.shadow = light.castShadow;

                if ( light.castShadow ) {

                    shadow = light.shadow;

                    uniforms.shadowBias = shadow.bias;
                    uniforms.shadowRadius = shadow.radius;
                    uniforms.shadowMapSize = shadow.mapSize;

                }

                _lights.directionalShadowMap[ directionalLength ] = shadowMap;
                _lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
                _lights.directional[ directionalLength ] = uniforms;

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                var uniforms = lightCache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.color.copy( color ).multiplyScalar( intensity );
                uniforms.distance = distance;

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                _vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( _vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                uniforms.coneCos = Math.cos( light.angle );
                uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
                uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;

                uniforms.shadow = light.castShadow;

                if ( light.castShadow ) {

                    shadow = light.shadow;

                    uniforms.shadowBias = shadow.bias;
                    uniforms.shadowRadius = shadow.radius;
                    uniforms.shadowMapSize = shadow.mapSize;

                }

                _lights.spotShadowMap[ spotLength ] = shadowMap;
                _lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
                _lights.spot[ spotLength ] = uniforms;

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                var uniforms = lightCache.get( light );

                // (a) intensity controls irradiance of entire light
                uniforms.color
                    .copy( color )
                    .multiplyScalar( intensity / ( light.width * light.height ) );

                // (b) intensity controls the radiance per light area
                // uniforms.color.copy( color ).multiplyScalar( intensity );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                // extract local rotation of light to derive width/height half vectors
                _matrix42.identity();
                _matrix4.copy( light.matrixWorld );
                _matrix4.premultiply( viewMatrix );
                _matrix42.extractRotation( _matrix4 );

                uniforms.halfWidth.set( light.width * 0.5,                0.0, 0.0 );
                uniforms.halfHeight.set(              0.0, light.height * 0.5, 0.0 );

                uniforms.halfWidth.applyMatrix4( _matrix42 );
                uniforms.halfHeight.applyMatrix4( _matrix42 );

                // TODO (abelnation): RectAreaLight distance?
                // uniforms.distance = distance;

                _lights.rectArea[ rectAreaLength ] = uniforms;

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                var uniforms = lightCache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.distance = light.distance;
                uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;

                uniforms.shadow = light.castShadow;

                if ( light.castShadow ) {

                    shadow = light.shadow;

                    uniforms.shadowBias = shadow.bias;
                    uniforms.shadowRadius = shadow.radius;
                    uniforms.shadowMapSize = shadow.mapSize;

                }

                _lights.pointShadowMap[ pointLength ] = shadowMap;
                _lights.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
                _lights.point[ pointLength ] = uniforms;

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                var uniforms = lightCache.get( light );

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                uniforms.direction.transformDirection( viewMatrix );
                uniforms.direction.normalize();

                uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
                uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );

                _lights.hemi[ hemiLength ] = uniforms;

                hemiLength ++;

            }

        }

        _lights.ambient[ 0 ] = r;
        _lights.ambient[ 1 ] = g;
        _lights.ambient[ 2 ] = b;

        _lights.directional.length = directionalLength;
        _lights.spot.length = spotLength;
        _lights.rectArea.length = rectAreaLength;
        _lights.point.length = pointLength;
        _lights.hemi.length = hemiLength;

        // TODO (sam-g-steel) why aren't we using join
        _lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length;

    }

    // GL state setting

    this.setFaceCulling = function ( cullFace, frontFaceDirection ) {

        state.setCullFace( cullFace );
        state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );

    };

    // Textures

    function allocTextureUnit() {

        var textureUnit = _usedTextureUnits;

        if ( textureUnit >= capabilities.maxTextures ) {

            console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );

        }

        _usedTextureUnits += 1;

        return textureUnit;

    }

    this.allocTextureUnit = allocTextureUnit;

    // this.setTexture2D = setTexture2D;
    this.setTexture2D = ( function () {

        var warned = false;

        // backwards compatibility: peel texture.texture
        return function setTexture2D( texture, slot ) {

            if ( texture && texture.isWebGLRenderTarget ) {

                if ( ! warned ) {

                    console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." );
                    warned = true;

                }

                texture = texture.texture;

            }

            textures.setTexture2D( texture, slot );

        };

    }() );

    this.setTexture = ( function () {

        var warned = false;

        return function setTexture( texture, slot ) {

            if ( ! warned ) {

                console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." );
                warned = true;

            }

            textures.setTexture2D( texture, slot );

        };

    }() );

    this.setTextureCube = ( function () {

        var warned = false;

        return function setTextureCube( texture, slot ) {

            // backwards compatibility: peel texture.texture
            if ( texture && texture.isWebGLRenderTargetCube ) {

                if ( ! warned ) {

                    console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
                    warned = true;

                }

                texture = texture.texture;

            }

            // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
            // TODO: unify these code paths
            if ( ( texture && texture.isCubeTexture ) ||
                ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {

                // CompressedTexture can have Array in image :/

                // this function alone should take care of cube textures
                textures.setTextureCube( texture, slot );

            } else {

                // assumed: texture property of THREE.WebGLRenderTargetCube

                textures.setTextureCubeDynamic( texture, slot );

            }

        };

    }() );

    this.getRenderTarget = function () {

        return _currentRenderTarget;

    };

    this.setRenderTarget = function ( renderTarget ) {

        _currentRenderTarget = renderTarget;

        if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {

            textures.setupRenderTarget( renderTarget );

        }

        var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
        var framebuffer;

        if ( renderTarget ) {

            var renderTargetProperties = properties.get( renderTarget );

            if ( isCube ) {

                framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ];

            } else {

                framebuffer = renderTargetProperties.__webglFramebuffer;

            }

            _currentScissor.copy( renderTarget.scissor );
            _currentScissorTest = renderTarget.scissorTest;

            _currentViewport.copy( renderTarget.viewport );

        } else {

            framebuffer = null;

            _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );
            _currentScissorTest = _scissorTest;

            _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );

        }

        if ( _currentFramebuffer !== framebuffer ) {

            _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
            _currentFramebuffer = framebuffer;

        }

        state.scissor( _currentScissor );
        state.setScissorTest( _currentScissorTest );

        state.viewport( _currentViewport );

        if ( isCube ) {

            var textureProperties = properties.get( renderTarget.texture );
            _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );

        }

    };

    this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {

        if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {

            console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
            return;

        }

        var framebuffer = properties.get( renderTarget ).__webglFramebuffer;

        if ( framebuffer ) {

            var restore = false;

            if ( framebuffer !== _currentFramebuffer ) {

                _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

                restore = true;

            }

            try {

                var texture = renderTarget.texture;
                var textureFormat = texture.format;
                var textureType = texture.type;

                if ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {

                    console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
                    return;

                }

                if ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)
                    ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
                    ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {

                    console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
                    return;

                }

                if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {

                    // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)

                    if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {

                        _gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer );

                    }

                } else {

                    console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );

                }

            } finally {

                if ( restore ) {

                    _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );

                }

            }

        }

    };

    // Map three.js constants to WebGL constants

    function paramThreeToGL( p ) {

        var extension;

        if ( p === RepeatWrapping ) return _gl.REPEAT;
        if ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
        if ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;

        if ( p === NearestFilter ) return _gl.NEAREST;
        if ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
        if ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;

        if ( p === LinearFilter ) return _gl.LINEAR;
        if ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
        if ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;

        if ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE;
        if ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
        if ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
        if ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;

        if ( p === ByteType ) return _gl.BYTE;
        if ( p === ShortType ) return _gl.SHORT;
        if ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT;
        if ( p === IntType ) return _gl.INT;
        if ( p === UnsignedIntType ) return _gl.UNSIGNED_INT;
        if ( p === FloatType ) return _gl.FLOAT;

        if ( p === HalfFloatType ) {

            extension = extensions.get( 'OES_texture_half_float' );

            if ( extension !== null ) return extension.HALF_FLOAT_OES;

        }

        if ( p === AlphaFormat ) return _gl.ALPHA;
        if ( p === RGBFormat ) return _gl.RGB;
        if ( p === RGBAFormat ) return _gl.RGBA;
        if ( p === LuminanceFormat ) return _gl.LUMINANCE;
        if ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
        if ( p === DepthFormat ) return _gl.DEPTH_COMPONENT;
        if ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL;

        if ( p === AddEquation ) return _gl.FUNC_ADD;
        if ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT;
        if ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;

        if ( p === ZeroFactor ) return _gl.ZERO;
        if ( p === OneFactor ) return _gl.ONE;
        if ( p === SrcColorFactor ) return _gl.SRC_COLOR;
        if ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
        if ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA;
        if ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
        if ( p === DstAlphaFactor ) return _gl.DST_ALPHA;
        if ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;

        if ( p === DstColorFactor ) return _gl.DST_COLOR;
        if ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
        if ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;

        if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
            p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );

            if ( extension !== null ) {

                if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
                if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
                if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
                if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;

            }

        }

        if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
            p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );

            if ( extension !== null ) {

                if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
                if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
                if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
                if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;

            }

        }

        if ( p === RGB_ETC1_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_etc1' );

            if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;

        }

        if ( p === MinEquation || p === MaxEquation ) {

            extension = extensions.get( 'EXT_blend_minmax' );

            if ( extension !== null ) {

                if ( p === MinEquation ) return extension.MIN_EXT;
                if ( p === MaxEquation ) return extension.MAX_EXT;

            }

        }

        if ( p === UnsignedInt248Type ) {

            extension = extensions.get( 'WEBGL_depth_texture' );

            if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;

        }

        return 0;

    }

}

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function FogExp2 ( color, density ) {

    this.name = '';

    this.color = new Color( color );
    this.density = ( density !== undefined ) ? density : 0.00025;

}

FogExp2.prototype.isFogExp2 = true;

FogExp2.prototype.clone = function () {

    return new FogExp2( this.color.getHex(), this.density );

};

FogExp2.prototype.toJSON = function ( meta ) {

    return {
        type: 'FogExp2',
        color: this.color.getHex(),
        density: this.density
    };

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function Fog ( color, near, far ) {

    this.name = '';

    this.color = new Color( color );

    this.near = ( near !== undefined ) ? near : 1;
    this.far = ( far !== undefined ) ? far : 1000;

}

Fog.prototype.isFog = true;

Fog.prototype.clone = function () {

    return new Fog( this.color.getHex(), this.near, this.far );

};

Fog.prototype.toJSON = function ( meta ) {

    return {
        type: 'Fog',
        color: this.color.getHex(),
        near: this.near,
        far: this.far
    };

};

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Scene () {

    Object3D.call( this );

    this.type = 'Scene';

    this.background = null;
    this.fog = null;
    this.overrideMaterial = null;

    this.autoUpdate = true; // checked by the renderer

}

Scene.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Scene,

    copy: function ( source, recursive ) {

        Object3D.prototype.copy.call( this, source, recursive );

        if ( source.background !== null ) this.background = source.background.clone();
        if ( source.fog !== null ) this.fog = source.fog.clone();
        if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();

        this.autoUpdate = source.autoUpdate;
        this.matrixAutoUpdate = source.matrixAutoUpdate;

        return this;

    },

    toJSON: function ( meta ) {

        var data = Object3D.prototype.toJSON.call( this, meta );

        if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
        if ( this.fog !== null ) data.object.fog = this.fog.toJSON();

        return data;

    }

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function LensFlare( texture, size, distance, blending, color ) {

    Object3D.call( this );

    this.lensFlares = [];

    this.positionScreen = new Vector3();
    this.customUpdateCallback = undefined;

    if ( texture !== undefined ) {

        this.add( texture, size, distance, blending, color );

    }

}

LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: LensFlare,

    isLensFlare: true,

    copy: function ( source ) {

        Object3D.prototype.copy.call( this, source );

        this.positionScreen.copy( source.positionScreen );
        this.customUpdateCallback = source.customUpdateCallback;

        for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) {

            this.lensFlares.push( source.lensFlares[ i ] );

        }

        return this;

    },

    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 Color( 0xffffff );
        if ( blending === undefined ) blending = 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 in front z = 1 is back
            scale: 1,         // scale
            rotation: 0,         // 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.
     */

    updateLensFlares: function () {

        var f, fl = this.lensFlares.length;
        var flare;
        var vecX = - this.positionScreen.x * 2;
        var vecY = - this.positionScreen.y * 2;

        for ( f = 0; f < fl; f ++ ) {

            flare = this.lensFlares[ f ];

            flare.x = this.positionScreen.x + vecX * flare.distance;
            flare.y = this.positionScreen.y + vecY * flare.distance;

            flare.wantedRotation = flare.x * Math.PI * 0.25;
            flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;

        }

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *    uvOffset: new THREE.Vector2(),
 *    uvScale: new THREE.Vector2()
 * }
 */

function SpriteMaterial( parameters ) {

    Material.call( this );

    this.type = 'SpriteMaterial';

    this.color = new Color( 0xffffff );
    this.map = null;

    this.rotation = 0;

    this.fog = false;
    this.lights = false;

    this.setValues( parameters );

}

SpriteMaterial.prototype = Object.create( Material.prototype );
SpriteMaterial.prototype.constructor = SpriteMaterial;
SpriteMaterial.prototype.isSpriteMaterial = true;

SpriteMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );
    this.map = source.map;

    this.rotation = source.rotation;

    return this;

};

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function Sprite( material ) {

    Object3D.call( this );

    this.type = 'Sprite';

    this.material = ( material !== undefined ) ? material : new SpriteMaterial();

}

Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Sprite,

    isSprite: true,

    raycast: ( function () {

        var intersectPoint = new Vector3();
        var worldPosition = new Vector3();
        var worldScale = new Vector3();

        return function raycast( raycaster, intersects ) {

            worldPosition.setFromMatrixPosition( this.matrixWorld );
            raycaster.ray.closestPointToPoint( worldPosition, intersectPoint );

            worldScale.setFromMatrixScale( this.matrixWorld );
            var guessSizeSq = worldScale.x * worldScale.y / 4;

            if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;

            var distance = raycaster.ray.origin.distanceTo( intersectPoint );

            if ( distance < raycaster.near || distance > raycaster.far ) return;

            intersects.push( {

                distance: distance,
                point: intersectPoint.clone(),
                face: null,
                object: this

            } );

        };

    }() ),

    clone: function () {

        return new this.constructor( this.material ).copy( this );

    }

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

function LOD() {

    Object3D.call( this );

    this.type = 'LOD';

    Object.defineProperties( this, {
        levels: {
            enumerable: true,
            value: []
        }
    } );

}

LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: LOD,

    copy: function ( source ) {

        Object3D.prototype.copy.call( this, source, false );

        var levels = source.levels;

        for ( var i = 0, l = levels.length; i < l; i ++ ) {

            var level = levels[ i ];

            this.addLevel( level.object.clone(), level.distance );

        }

        return this;

    },

    addLevel: function ( object, distance ) {

        if ( distance === undefined ) distance = 0;

        distance = Math.abs( distance );

        var levels = this.levels;

        for ( var l = 0; l < levels.length; l ++ ) {

            if ( distance < levels[ l ].distance ) {

                break;

            }

        }

        levels.splice( l, 0, { distance: distance, object: object } );

        this.add( object );

    },

    getObjectForDistance: function ( distance ) {

        var levels = this.levels;

        for ( var i = 1, l = levels.length; i < l; i ++ ) {

            if ( distance < levels[ i ].distance ) {

                break;

            }

        }

        return levels[ i - 1 ].object;

    },

    raycast: ( function () {

        var matrixPosition = new Vector3();

        return function raycast( raycaster, intersects ) {

            matrixPosition.setFromMatrixPosition( this.matrixWorld );

            var distance = raycaster.ray.origin.distanceTo( matrixPosition );

            this.getObjectForDistance( distance ).raycast( raycaster, intersects );

        };

    }() ),

    update: function () {

        var v1 = new Vector3();
        var v2 = new Vector3();

        return function update( camera ) {

            var levels = this.levels;

            if ( levels.length > 1 ) {

                v1.setFromMatrixPosition( camera.matrixWorld );
                v2.setFromMatrixPosition( this.matrixWorld );

                var distance = v1.distanceTo( v2 );

                levels[ 0 ].object.visible = true;

                for ( var i = 1, l = levels.length; i < l; i ++ ) {

                    if ( distance >= levels[ i ].distance ) {

                        levels[ i - 1 ].object.visible = false;
                        levels[ i ].object.visible = true;

                    } else {

                        break;

                    }

                }

                for ( ; i < l; i ++ ) {

                    levels[ i ].object.visible = false;

                }

            }

        };

    }(),

    toJSON: function ( meta ) {

        var data = Object3D.prototype.toJSON.call( this, meta );

        data.object.levels = [];

        var levels = this.levels;

        for ( var i = 0, l = levels.length; i < l; i ++ ) {

            var level = levels[ i ];

            data.object.levels.push( {
                object: level.object.uuid,
                distance: level.distance
            } );

        }

        return data;

    }

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author michael guerrero / http://realitymeltdown.com
 * @author ikerr / http://verold.com
 */

function Skeleton( bones, boneInverses ) {

    // copy the bone array

    bones = bones || [];

    this.bones = bones.slice( 0 );
    this.boneMatrices = new Float32Array( this.bones.length * 16 );

    // 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 {

            console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );

            this.boneInverses = [];

            for ( var i = 0, il = this.bones.length; i < il; i ++ ) {

                this.boneInverses.push( new Matrix4() );

            }

        }

    }

}

Object.assign( Skeleton.prototype, {

    calculateInverses: function () {

        this.boneInverses = [];

        for ( var i = 0, il = this.bones.length; i < il; i ++ ) {

            var inverse = new Matrix4();

            if ( this.bones[ i ] ) {

                inverse.getInverse( this.bones[ i ].matrixWorld );

            }

            this.boneInverses.push( inverse );

        }

    },

    pose: function () {

        var bone, i, il;

        // recover the bind-time world matrices

        for ( i = 0, il = this.bones.length; i < il; i ++ ) {

            bone = this.bones[ i ];

            if ( bone ) {

                bone.matrixWorld.getInverse( this.boneInverses[ i ] );

            }

        }

        // compute the local matrices, positions, rotations and scales

        for ( i = 0, il = this.bones.length; i < il; i ++ ) {

            bone = this.bones[ i ];

            if ( bone ) {

                if ( bone.parent && bone.parent.isBone ) {

                    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 );

            }

        }

    },

    update: ( function () {

        var offsetMatrix = new Matrix4();
        var identityMatrix = new Matrix4();

        return function update() {

            var bones = this.bones;
            var boneInverses = this.boneInverses;
            var boneMatrices = this.boneMatrices;
            var boneTexture = this.boneTexture;

            // flatten bone matrices to array

            for ( var i = 0, il = bones.length; i < il; i ++ ) {

                // compute the offset between the current and the original transform

                var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix;

                offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
                offsetMatrix.toArray( boneMatrices, i * 16 );

            }

            if ( boneTexture !== undefined ) {

                boneTexture.needsUpdate = true;

            }

        };

    } )(),

    clone: function () {

        return new Skeleton( this.bones, this.boneInverses );

    }

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author ikerr / http://verold.com
 */

function Bone() {

    Object3D.call( this );

    this.type = 'Bone';

}

Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Bone,

    isBone: true

} );

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author ikerr / http://verold.com
 */

function SkinnedMesh( geometry, material ) {

    Mesh.call( this, geometry, material );

    this.type = 'SkinnedMesh';

    this.bindMode = 'attached';
    this.bindMatrix = new Matrix4();
    this.bindMatrixInverse = new Matrix4();

    var bones = this.initBones();
    var skeleton = new Skeleton( bones );

    this.bind( skeleton, this.matrixWorld );

    this.normalizeSkinWeights();

}

SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {

    constructor: SkinnedMesh,

    isSkinnedMesh: true,

    initBones: function () {

        var bones = [], bone, gbone;
        var i, il;

        if ( this.geometry && this.geometry.bones !== undefined ) {

            // first, create array of 'Bone' objects from geometry data

            for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {

                gbone = this.geometry.bones[ i ];

                // create new 'Bone' object

                bone = new Bone();
                bones.push( bone );

                // apply values

                bone.name = gbone.name;
                bone.position.fromArray( gbone.pos );
                bone.quaternion.fromArray( gbone.rotq );
                if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );

            }

            // second, create bone hierarchy

            for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {

                gbone = this.geometry.bones[ i ];

                if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {

                    // subsequent bones in the hierarchy

                    bones[ gbone.parent ].add( bones[ i ] );

                } else {

                    // topmost bone, immediate child of the skinned mesh

                    this.add( bones[ i ] );

                }

            }

        }

        // now the bones are part of the scene graph and children of the skinned mesh.
        // let's update the corresponding matrices

        this.updateMatrixWorld( true );

        return bones;

    },

    bind: function ( skeleton, bindMatrix ) {

        this.skeleton = skeleton;

        if ( bindMatrix === undefined ) {

            this.updateMatrixWorld( true );

            this.skeleton.calculateInverses();

            bindMatrix = this.matrixWorld;

        }

        this.bindMatrix.copy( bindMatrix );
        this.bindMatrixInverse.getInverse( bindMatrix );

    },

    pose: function () {

        this.skeleton.pose();

    },

    normalizeSkinWeights: function () {

        var scale, i;

        if ( this.geometry && this.geometry.isGeometry ) {

            for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {

                var sw = this.geometry.skinWeights[ i ];

                scale = 1.0 / sw.lengthManhattan();

                if ( scale !== Infinity ) {

                    sw.multiplyScalar( scale );

                } else {

                    sw.set( 1, 0, 0, 0 ); // do something reasonable

                }

            }

        } else if ( this.geometry && this.geometry.isBufferGeometry ) {

            var vec = new Vector4();

            var skinWeight = this.geometry.attributes.skinWeight;

            for ( i = 0; i < skinWeight.count; i ++ ) {

                vec.x = skinWeight.getX( i );
                vec.y = skinWeight.getY( i );
                vec.z = skinWeight.getZ( i );
                vec.w = skinWeight.getW( i );

                scale = 1.0 / vec.lengthManhattan();

                if ( scale !== Infinity ) {

                    vec.multiplyScalar( scale );

                } else {

                    vec.set( 1, 0, 0, 0 ); // do something reasonable

                }

                skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );

            }

        }

    },

    updateMatrixWorld: function ( force ) {

        Mesh.prototype.updateMatrixWorld.call( this, force );

        if ( this.bindMode === 'attached' ) {

            this.bindMatrixInverse.getInverse( this.matrixWorld );

        } else if ( this.bindMode === 'detached' ) {

            this.bindMatrixInverse.getInverse( this.bindMatrix );

        } else {

            console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );

        }

    },

    clone: function () {

        return new this.constructor( this.geometry, this.material ).copy( this );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *
 *  linewidth: <float>,
 *  linecap: "round",
 *  linejoin: "round"
 * }
 */

function LineBasicMaterial( parameters ) {

    Material.call( this );

    this.type = 'LineBasicMaterial';

    this.color = new Color( 0xffffff );

    this.linewidth = 1;
    this.linecap = 'round';
    this.linejoin = 'round';

    this.lights = false;

    this.setValues( parameters );

}

LineBasicMaterial.prototype = Object.create( Material.prototype );
LineBasicMaterial.prototype.constructor = LineBasicMaterial;

LineBasicMaterial.prototype.isLineBasicMaterial = true;

LineBasicMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );

    this.linewidth = source.linewidth;
    this.linecap = source.linecap;
    this.linejoin = source.linejoin;

    return this;

};

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Line( geometry, material, mode ) {

    if ( mode === 1 ) {

        console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );
        return new LineSegments( geometry, material );

    }

    Object3D.call( this );

    this.type = 'Line';

    this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
    this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );

}

Line.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Line,

    isLine: true,

    raycast: ( function () {

        var inverseMatrix = new Matrix4();
        var ray = new Ray();
        var sphere = new Sphere();

        return function raycast( raycaster, intersects ) {

            var precision = raycaster.linePrecision;
            var precisionSq = precision * precision;

            var geometry = this.geometry;
            var matrixWorld = this.matrixWorld;

            // Checking boundingSphere distance to ray

            if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

            sphere.copy( geometry.boundingSphere );
            sphere.applyMatrix4( matrixWorld );

            if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;

            //

            inverseMatrix.getInverse( matrixWorld );
            ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

            var vStart = new Vector3();
            var vEnd = new Vector3();
            var interSegment = new Vector3();
            var interRay = new Vector3();
            var step = (this && this.isLineSegments) ? 2 : 1;

            if ( geometry.isBufferGeometry ) {

                var index = geometry.index;
                var attributes = geometry.attributes;
                var positions = attributes.position.array;

                if ( index !== null ) {

                    var indices = index.array;

                    for ( var i = 0, l = indices.length - 1; i < l; i += step ) {

                        var a = indices[ i ];
                        var b = 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;

                        interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation

                        var distance = raycaster.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 {

                    for ( var i = 0, l = positions.length / 3 - 1; i < l; 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;

                        interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation

                        var distance = raycaster.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.isGeometry ) {

                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;

                    interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation

                    var distance = raycaster.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

                    } );

                }

            }

        };

    }() ),

    clone: function () {

        return new this.constructor( this.geometry, this.material ).copy( this );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function LineSegments( geometry, material ) {

    Line.call( this, geometry, material );

    this.type = 'LineSegments';

}

LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {

    constructor: LineSegments,

    isLineSegments: true

} );

/**
 * @author mgreter / http://github.com/mgreter
 */

function LineLoop( geometry, material ) {

    Line.call( this, geometry, material );

    this.type = 'LineLoop';

}

LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {

    constructor: LineLoop,

    isLineLoop: true,

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  size: <float>,
 *  sizeAttenuation: <bool>
 * }
 */

function PointsMaterial( parameters ) {

    Material.call( this );

    this.type = 'PointsMaterial';

    this.color = new Color( 0xffffff );

    this.map = null;

    this.size = 1;
    this.sizeAttenuation = true;

    this.lights = false;

    this.setValues( parameters );

}

PointsMaterial.prototype = Object.create( Material.prototype );
PointsMaterial.prototype.constructor = PointsMaterial;

PointsMaterial.prototype.isPointsMaterial = true;

PointsMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );

    this.map = source.map;

    this.size = source.size;
    this.sizeAttenuation = source.sizeAttenuation;

    return this;

};

/**
 * @author alteredq / http://alteredqualia.com/
 */

function Points( geometry, material ) {

    Object3D.call( this );

    this.type = 'Points';

    this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
    this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );

}

Points.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Points,

    isPoints: true,

    raycast: ( function () {

        var inverseMatrix = new Matrix4();
        var ray = new Ray();
        var sphere = new Sphere();

        return function raycast( raycaster, intersects ) {

            var object = this;
            var geometry = this.geometry;
            var matrixWorld = this.matrixWorld;
            var threshold = raycaster.params.Points.threshold;

            // Checking boundingSphere distance to ray

            if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

            sphere.copy( geometry.boundingSphere );
            sphere.applyMatrix4( matrixWorld );
            sphere.radius += threshold;

            if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;

            //

            inverseMatrix.getInverse( matrixWorld );
            ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

            var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
            var localThresholdSq = localThreshold * localThreshold;
            var position = new Vector3();

            function testPoint( point, index ) {

                var rayPointDistanceSq = ray.distanceSqToPoint( point );

                if ( rayPointDistanceSq < localThresholdSq ) {

                    var intersectPoint = ray.closestPointToPoint( point );
                    intersectPoint.applyMatrix4( matrixWorld );

                    var distance = raycaster.ray.origin.distanceTo( intersectPoint );

                    if ( distance < raycaster.near || distance > raycaster.far ) return;

                    intersects.push( {

                        distance: distance,
                        distanceToRay: Math.sqrt( rayPointDistanceSq ),
                        point: intersectPoint.clone(),
                        index: index,
                        face: null,
                        object: object

                    } );

                }

            }

            if ( geometry.isBufferGeometry ) {

                var index = geometry.index;
                var attributes = geometry.attributes;
                var positions = attributes.position.array;

                if ( index !== null ) {

                    var indices = index.array;

                    for ( var i = 0, il = indices.length; i < il; i ++ ) {

                        var a = indices[ i ];

                        position.fromArray( positions, a * 3 );

                        testPoint( position, a );

                    }

                } else {

                    for ( var i = 0, l = positions.length / 3; i < l; i ++ ) {

                        position.fromArray( positions, i * 3 );

                        testPoint( position, i );

                    }

                }

            } else {

                var vertices = geometry.vertices;

                for ( var i = 0, l = vertices.length; i < l; i ++ ) {

                    testPoint( vertices[ i ], i );

                }

            }

        };

    }() ),

    clone: function () {

        return new this.constructor( this.geometry, this.material ).copy( this );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Group() {

    Object3D.call( this );

    this.type = 'Group';

}

Group.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Group

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {

    Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

    this.generateMipmaps = false;

    var scope = this;

    function update() {

        requestAnimationFrame( update );

        if ( video.readyState >= video.HAVE_CURRENT_DATA ) {

            scope.needsUpdate = true;

        }

    }

    update();

}

VideoTexture.prototype = Object.create( Texture.prototype );
VideoTexture.prototype.constructor = VideoTexture;

/**
 * @author alteredq / http://alteredqualia.com/
 */

function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {

    Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );

    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;

}

CompressedTexture.prototype = Object.create( Texture.prototype );
CompressedTexture.prototype.constructor = CompressedTexture;

CompressedTexture.prototype.isCompressedTexture = true;

/**
 * @author mrdoob / http://mrdoob.com/
 */

function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {

    Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

    this.needsUpdate = true;

}

CanvasTexture.prototype = Object.create( Texture.prototype );
CanvasTexture.prototype.constructor = CanvasTexture;

/**
 * @author Matt DesLauriers / @mattdesl
 * @author atix / arthursilber.de
 */

function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {

    format = format !== undefined ? format : DepthFormat;

    if ( format !== DepthFormat && format !== DepthStencilFormat ) {

        throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' )

    }

    if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
    if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;

    Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

    this.image = { width: width, height: height };

    this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
    this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;

    this.flipY = false;
    this.generateMipmaps    = false;

}

DepthTexture.prototype = Object.create( Texture.prototype );
DepthTexture.prototype.constructor = DepthTexture;
DepthTexture.prototype.isDepthTexture = true;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

function WireframeGeometry( geometry ) {

    BufferGeometry.call( this );

    this.type = 'WireframeGeometry';

    // buffer

    var vertices = [];

    // helper variables

    var i, j, l, o, ol;
    var edge = [ 0, 0 ], edges = {}, e, edge1, edge2;
    var key, keys = [ 'a', 'b', 'c' ];
    var vertex;

    // different logic for Geometry and BufferGeometry

    if ( geometry && geometry.isGeometry ) {

        // create a data structure that contains all edges without duplicates

        var faces = geometry.faces;

        for ( i = 0, l = faces.length; i < l; i ++ ) {

            var face = faces[ i ];

            for ( j = 0; j < 3; j ++ ) {

                edge1 = face[ keys[ j ] ];
                edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
                edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
                edge[ 1 ] = Math.max( edge1, edge2 );

                key = edge[ 0 ] + ',' + edge[ 1 ];

                if ( edges[ key ] === undefined ) {

                    edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };

                }

            }

        }

        // generate vertices

        for ( key in edges ) {

            e = edges[ key ];

            vertex = geometry.vertices[ e.index1 ];
            vertices.push( vertex.x, vertex.y, vertex.z );

            vertex = geometry.vertices[ e.index2 ];
            vertices.push( vertex.x, vertex.y, vertex.z );

        }

    } else if ( geometry && geometry.isBufferGeometry ) {

        var position, indices, groups;
        var group, start, count;
        var index1, index2;

        vertex = new Vector3();

        if ( geometry.index !== null ) {

            // indexed BufferGeometry

            position = geometry.attributes.position;
            indices = geometry.index;
            groups = geometry.groups;

            if ( groups.length === 0 ) {

                groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];

            }

            // create a data structure that contains all eges without duplicates

            for ( o = 0, ol = groups.length; o < ol; ++ o ) {

                group = groups[ o ];

                start = group.start;
                count = group.count;

                for ( i = start, l = ( start + count ); i < l; i += 3 ) {

                    for ( j = 0; j < 3; j ++ ) {

                        edge1 = indices.getX( i + j );
                        edge2 = indices.getX( i + ( j + 1 ) % 3 );
                        edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
                        edge[ 1 ] = Math.max( edge1, edge2 );

                        key = edge[ 0 ] + ',' + edge[ 1 ];

                        if ( edges[ key ] === undefined ) {

                            edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };

                        }

                    }

                }

            }

            // generate vertices

            for ( key in edges ) {

                e = edges[ key ];

                vertex.fromBufferAttribute( position, e.index1 );
                vertices.push( vertex.x, vertex.y, vertex.z );

                vertex.fromBufferAttribute( position, e.index2 );
                vertices.push( vertex.x, vertex.y, vertex.z );

            }

        } else {

            // non-indexed BufferGeometry

            position = geometry.attributes.position;

            for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {

                for ( j = 0; j < 3; j ++ ) {

                    // three edges per triangle, an edge is represented as (index1, index2)
                    // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)

                    index1 = 3 * i + j;
                    vertex.fromBufferAttribute( position, index1 );
                    vertices.push( vertex.x, vertex.y, vertex.z );

                    index2 = 3 * i + ( ( j + 1 ) % 3 );
                    vertex.fromBufferAttribute( position, index2 );
                    vertices.push( vertex.x, vertex.y, vertex.z );

                }

            }

        }

    }

    // build geometry

    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );

}

WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
WireframeGeometry.prototype.constructor = WireframeGeometry;

/**
 * @author zz85 / https://github.com/zz85
 * @author Mugen87 / https://github.com/Mugen87
 *
 * Parametric Surfaces Geometry
 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 */

// ParametricGeometry

function ParametricGeometry( func, slices, stacks ) {

    Geometry.call( this );

    this.type = 'ParametricGeometry';

    this.parameters = {
        func: func,
        slices: slices,
        stacks: stacks
    };

    this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
    this.mergeVertices();

}

ParametricGeometry.prototype = Object.create( Geometry.prototype );
ParametricGeometry.prototype.constructor = ParametricGeometry;

// ParametricBufferGeometry

function ParametricBufferGeometry( func, slices, stacks ) {

    BufferGeometry.call( this );

    this.type = 'ParametricBufferGeometry';

    this.parameters = {
        func: func,
        slices: slices,
        stacks: stacks
    };

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    var EPS = 0.00001;

    var normal = new Vector3();

    var p0 = new Vector3(), p1 = new Vector3();
    var pu = new Vector3(), pv = new Vector3();

    var i, j;

    // generate vertices, normals and uvs

    var sliceCount = slices + 1;

    for ( i = 0; i <= stacks; i ++ ) {

        var v = i / stacks;

        for ( j = 0; j <= slices; j ++ ) {

            var u = j / slices;

            // vertex

            p0 = func( u, v, p0 );
            vertices.push( p0.x, p0.y, p0.z );

            // normal

            // approximate tangent vectors via finite differences

            if ( u - EPS >= 0 ) {

                p1 = func( u - EPS, v, p1 );
                pu.subVectors( p0, p1 );

            } else {

                p1 = func( u + EPS, v, p1 );
                pu.subVectors( p1, p0 );

            }

            if ( v - EPS >= 0 ) {

                p1 = func( u, v - EPS, p1 );
                pv.subVectors( p0, p1 );

            } else {

                p1 = func( u, v + EPS, p1 );
                pv.subVectors( p1, p0 );

            }

            // cross product of tangent vectors returns surface normal

            normal.crossVectors( pu, pv ).normalize();
            normals.push( normal.x, normal.y, normal.z );

            // uv

            uvs.push( u, v );

        }

    }

    // generate indices

    for ( i = 0; i < stacks; i ++ ) {

        for ( j = 0; j < slices; j ++ ) {

            var a = i * sliceCount + j;
            var b = i * sliceCount + j + 1;
            var c = ( i + 1 ) * sliceCount + j + 1;
            var d = ( i + 1 ) * sliceCount + j;

            // faces one and two

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;

/**
 * @author clockworkgeek / https://github.com/clockworkgeek
 * @author timothypratley / https://github.com/timothypratley
 * @author WestLangley / http://github.com/WestLangley
 * @author Mugen87 / https://github.com/Mugen87
 */

// PolyhedronGeometry

function PolyhedronGeometry( vertices, indices, radius, detail ) {

    Geometry.call( this );

    this.type = 'PolyhedronGeometry';

    this.parameters = {
        vertices: vertices,
        indices: indices,
        radius: radius,
        detail: detail
    };

    this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
    this.mergeVertices();

}

PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;

// PolyhedronBufferGeometry

function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {

    BufferGeometry.call( this );

    this.type = 'PolyhedronBufferGeometry';

    this.parameters = {
        vertices: vertices,
        indices: indices,
        radius: radius,
        detail: detail
    };

    radius = radius || 1;
    detail = detail || 0;

    // default buffer data

    var vertexBuffer = [];
    var uvBuffer = [];

    // the subdivision creates the vertex buffer data

    subdivide( detail );

    // all vertices should lie on a conceptual sphere with a given radius

    appplyRadius( radius );

    // finally, create the uv data

    generateUVs();

    // build non-indexed geometry

    this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );

    if ( detail === 0 ) {

        this.computeVertexNormals(); // flat normals

    } else {

        this.normalizeNormals(); // smooth normals

    }

    // helper functions

    function subdivide( detail ) {

        var a = new Vector3();
        var b = new Vector3();
        var c = new Vector3();

        // iterate over all faces and apply a subdivison with the given detail value

        for ( var i = 0; i < indices.length; i += 3 ) {

            // get the vertices of the face

            getVertexByIndex( indices[ i + 0 ], a );
            getVertexByIndex( indices[ i + 1 ], b );
            getVertexByIndex( indices[ i + 2 ], c );

            // perform subdivision

            subdivideFace( a, b, c, detail );

        }

    }

    function subdivideFace( a, b, c, detail ) {

        var cols = Math.pow( 2, detail );

        // we use this multidimensional array as a data structure for creating the subdivision

        var v = [];

        var i, j;

        // construct all of the vertices for this subdivision

        for ( i = 0; i <= cols; i ++ ) {

            v[ i ] = [];

            var aj = a.clone().lerp( c, i / cols );
            var bj = b.clone().lerp( c, i / cols );

            var rows = cols - i;

            for ( j = 0; j <= rows; j ++ ) {

                if ( j === 0 && i === cols ) {

                    v[ i ][ j ] = aj;

                } else {

                    v[ i ][ j ] = aj.clone().lerp( bj, j / rows );

                }

            }

        }

        // construct all of the faces

        for ( i = 0; i < cols; i ++ ) {

            for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {

                var k = Math.floor( j / 2 );

                if ( j % 2 === 0 ) {

                    pushVertex( v[ i ][ k + 1 ] );
                    pushVertex( v[ i + 1 ][ k ] );
                    pushVertex( v[ i ][ k ] );

                } else {

                    pushVertex( v[ i ][ k + 1 ] );
                    pushVertex( v[ i + 1 ][ k + 1 ] );
                    pushVertex( v[ i + 1 ][ k ] );

                }

            }

        }

    }

    function appplyRadius( radius ) {

        var vertex = new Vector3();

        // iterate over the entire buffer and apply the radius to each vertex

        for ( var i = 0; i < vertexBuffer.length; i += 3 ) {

            vertex.x = vertexBuffer[ i + 0 ];
            vertex.y = vertexBuffer[ i + 1 ];
            vertex.z = vertexBuffer[ i + 2 ];

            vertex.normalize().multiplyScalar( radius );

            vertexBuffer[ i + 0 ] = vertex.x;
            vertexBuffer[ i + 1 ] = vertex.y;
            vertexBuffer[ i + 2 ] = vertex.z;

        }

    }

    function generateUVs() {

        var vertex = new Vector3();

        for ( var i = 0; i < vertexBuffer.length; i += 3 ) {

            vertex.x = vertexBuffer[ i + 0 ];
            vertex.y = vertexBuffer[ i + 1 ];
            vertex.z = vertexBuffer[ i + 2 ];

            var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
            var v = inclination( vertex ) / Math.PI + 0.5;
            uvBuffer.push( u, 1 - v );

        }

        correctUVs();

        correctSeam();

    }

    function correctSeam() {

        // handle case when face straddles the seam, see #3269

        for ( var i = 0; i < uvBuffer.length; i += 6 ) {

            // uv data of a single face

            var x0 = uvBuffer[ i + 0 ];
            var x1 = uvBuffer[ i + 2 ];
            var x2 = uvBuffer[ i + 4 ];

            var max = Math.max( x0, x1, x2 );
            var min = Math.min( x0, x1, x2 );

            // 0.9 is somewhat arbitrary

            if ( max > 0.9 && min < 0.1 ) {

                if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
                if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
                if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;

            }

        }

    }

    function pushVertex( vertex ) {

        vertexBuffer.push( vertex.x, vertex.y, vertex.z );

    }

    function getVertexByIndex( index, vertex ) {

        var stride = index * 3;

        vertex.x = vertices[ stride + 0 ];
        vertex.y = vertices[ stride + 1 ];
        vertex.z = vertices[ stride + 2 ];

    }

    function correctUVs() {

        var a = new Vector3();
        var b = new Vector3();
        var c = new Vector3();

        var centroid = new Vector3();

        var uvA = new Vector2();
        var uvB = new Vector2();
        var uvC = new Vector2();

        for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {

            a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
            b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
            c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );

            uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
            uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
            uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );

            centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );

            var azi = azimuth( centroid );

            correctUV( uvA, j + 0, a, azi );
            correctUV( uvB, j + 2, b, azi );
            correctUV( uvC, j + 4, c, azi );

        }

    }

    function correctUV( uv, stride, vector, azimuth ) {

        if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {

            uvBuffer[ stride ] = uv.x - 1;

        }

        if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {

            uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;

        }

    }

    // 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 ) ) );

    }

}

PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;

/**
 * @author timothypratley / https://github.com/timothypratley
 * @author Mugen87 / https://github.com/Mugen87
 */

// TetrahedronGeometry

function TetrahedronGeometry( radius, detail ) {

    Geometry.call( this );

    this.type = 'TetrahedronGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

    this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
    this.mergeVertices();

}

TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;

// TetrahedronBufferGeometry

function TetrahedronBufferGeometry( 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
    ];

    PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

    this.type = 'TetrahedronBufferGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

}

TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;

/**
 * @author timothypratley / https://github.com/timothypratley
 * @author Mugen87 / https://github.com/Mugen87
 */

// OctahedronGeometry

function OctahedronGeometry( radius, detail ) {

    Geometry.call( this );

    this.type = 'OctahedronGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

    this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
    this.mergeVertices();

}

OctahedronGeometry.prototype = Object.create( Geometry.prototype );
OctahedronGeometry.prototype.constructor = OctahedronGeometry;

// OctahedronBufferGeometry

function OctahedronBufferGeometry( radius, 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
    ];

    PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

    this.type = 'OctahedronBufferGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

}

OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;

/**
 * @author timothypratley / https://github.com/timothypratley
 * @author Mugen87 / https://github.com/Mugen87
 */

// IcosahedronGeometry

function IcosahedronGeometry( radius, detail ) {

     Geometry.call( this );

    this.type = 'IcosahedronGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

    this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
    this.mergeVertices();

}

IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;

// IcosahedronBufferGeometry

function IcosahedronBufferGeometry( 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
    ];

    PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

    this.type = 'IcosahedronBufferGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

}

IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;

/**
 * @author Abe Pazos / https://hamoid.com
 * @author Mugen87 / https://github.com/Mugen87
 */

// DodecahedronGeometry

function DodecahedronGeometry( radius, detail ) {

    Geometry.call( this );

    this.type = 'DodecahedronGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

    this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
    this.mergeVertices();

}

DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;

// DodecahedronBufferGeometry

function DodecahedronBufferGeometry( radius, 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
    ];

    PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

    this.type = 'DodecahedronBufferGeometry';

    this.parameters = {
        radius: radius,
        detail: detail
    };

}

DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;

/**
 * @author oosmoxiecode / https://github.com/oosmoxiecode
 * @author WestLangley / https://github.com/WestLangley
 * @author zz85 / https://github.com/zz85
 * @author miningold / https://github.com/miningold
 * @author jonobr1 / https://github.com/jonobr1
 * @author Mugen87 / https://github.com/Mugen87
 *
 */

// TubeGeometry

function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {

    Geometry.call( this );

    this.type = 'TubeGeometry';

    this.parameters = {
        path: path,
        tubularSegments: tubularSegments,
        radius: radius,
        radialSegments: radialSegments,
        closed: closed
    };

    if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );

    var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );

    // expose internals

    this.tangents = bufferGeometry.tangents;
    this.normals = bufferGeometry.normals;
    this.binormals = bufferGeometry.binormals;

    // create geometry

    this.fromBufferGeometry( bufferGeometry );
    this.mergeVertices();

}

TubeGeometry.prototype = Object.create( Geometry.prototype );
TubeGeometry.prototype.constructor = TubeGeometry;

// TubeBufferGeometry

function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {

    BufferGeometry.call( this );

    this.type = 'TubeBufferGeometry';

    this.parameters = {
        path: path,
        tubularSegments: tubularSegments,
        radius: radius,
        radialSegments: radialSegments,
        closed: closed
    };

    tubularSegments = tubularSegments || 64;
    radius = radius || 1;
    radialSegments = radialSegments || 8;
    closed = closed || false;

    var frames = path.computeFrenetFrames( tubularSegments, closed );

    // expose internals

    this.tangents = frames.tangents;
    this.normals = frames.normals;
    this.binormals = frames.binormals;

    // helper variables

    var vertex = new Vector3();
    var normal = new Vector3();
    var uv = new Vector2();

    var i, j;

    // buffer

    var vertices = [];
    var normals = [];
    var uvs = [];
    var indices = [];

    // create buffer data

    generateBufferData();

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    // functions

    function generateBufferData() {

        for ( i = 0; i < tubularSegments; i ++ ) {

            generateSegment( i );

        }

        // if the geometry is not closed, generate the last row of vertices and normals
        // at the regular position on the given path
        //
        // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)

        generateSegment( ( closed === false ) ? tubularSegments : 0 );

        // uvs are generated in a separate function.
        // this makes it easy compute correct values for closed geometries

        generateUVs();

        // finally create faces

        generateIndices();

    }

    function generateSegment( i ) {

        // we use getPointAt to sample evenly distributed points from the given path

        var P = path.getPointAt( i / tubularSegments );

        // retrieve corresponding normal and binormal

        var N = frames.normals[ i ];
        var B = frames.binormals[ i ];

        // generate normals and vertices for the current segment

        for ( j = 0; j <= radialSegments; j ++ ) {

            var v = j / radialSegments * Math.PI * 2;

            var sin =   Math.sin( v );
            var cos = - Math.cos( v );

            // normal

            normal.x = ( cos * N.x + sin * B.x );
            normal.y = ( cos * N.y + sin * B.y );
            normal.z = ( cos * N.z + sin * B.z );
            normal.normalize();

            normals.push( normal.x, normal.y, normal.z );

            // vertex

            vertex.x = P.x + radius * normal.x;
            vertex.y = P.y + radius * normal.y;
            vertex.z = P.z + radius * normal.z;

            vertices.push( vertex.x, vertex.y, vertex.z );

        }

    }

    function generateIndices() {

        for ( j = 1; j <= tubularSegments; j ++ ) {

            for ( i = 1; i <= radialSegments; i ++ ) {

                var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
                var b = ( radialSegments + 1 ) * j + ( i - 1 );
                var c = ( radialSegments + 1 ) * j + i;
                var d = ( radialSegments + 1 ) * ( j - 1 ) + i;

                // faces

                indices.push( a, b, d );
                indices.push( b, c, d );

            }

        }

    }

    function generateUVs() {

        for ( i = 0; i <= tubularSegments; i ++ ) {

            for ( j = 0; j <= radialSegments; j ++ ) {

                uv.x = i / tubularSegments;
                uv.y = j / radialSegments;

                uvs.push( uv.x, uv.y );

            }

        }

    }

}

TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;

/**
 * @author oosmoxiecode
 * @author Mugen87 / https://github.com/Mugen87
 *
 * based on http://www.blackpawn.com/texts/pqtorus/
 */

// TorusKnotGeometry

function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {

    Geometry.call( this );

    this.type = 'TorusKnotGeometry';

    this.parameters = {
        radius: radius,
        tube: tube,
        tubularSegments: tubularSegments,
        radialSegments: radialSegments,
        p: p,
        q: q
    };

    if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );

    this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
    this.mergeVertices();

}

TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;

// TorusKnotBufferGeometry

function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {

    BufferGeometry.call( this );

    this.type = 'TorusKnotBufferGeometry';

    this.parameters = {
        radius: radius,
        tube: tube,
        tubularSegments: tubularSegments,
        radialSegments: radialSegments,
        p: p,
        q: q
    };

    radius = radius || 100;
    tube = tube || 40;
    tubularSegments = Math.floor( tubularSegments ) || 64;
    radialSegments = Math.floor( radialSegments ) || 8;
    p = p || 2;
    q = q || 3;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var i, j;

    var vertex = new Vector3();
    var normal = new Vector3();

    var P1 = new Vector3();
    var P2 = new Vector3();

    var B = new Vector3();
    var T = new Vector3();
    var N = new Vector3();

    // generate vertices, normals and uvs

    for ( i = 0; i <= tubularSegments; ++ i ) {

        // the radian "u" is used to calculate the position on the torus curve of the current tubular segement

        var u = i / tubularSegments * p * Math.PI * 2;

        // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
        // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions

        calculatePositionOnCurve( u, p, q, radius, P1 );
        calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );

        // calculate orthonormal basis

        T.subVectors( P2, P1 );
        N.addVectors( P2, P1 );
        B.crossVectors( T, N );
        N.crossVectors( B, T );

        // normalize B, N. T can be ignored, we don't use it

        B.normalize();
        N.normalize();

        for ( j = 0; j <= radialSegments; ++ j ) {

            // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
            // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.

            var v = j / radialSegments * Math.PI * 2;
            var cx = - tube * Math.cos( v );
            var cy = tube * Math.sin( v );

            // now calculate the final vertex position.
            // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve

            vertex.x = P1.x + ( cx * N.x + cy * B.x );
            vertex.y = P1.y + ( cx * N.y + cy * B.y );
            vertex.z = P1.z + ( cx * N.z + cy * B.z );

            vertices.push( vertex.x, vertex.y, vertex.z );

            // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)

            normal.subVectors( vertex, P1 ).normalize();

            normals.push( normal.x, normal.y, normal.z );

            // uv

            uvs.push( i / tubularSegments );
            uvs.push( j / radialSegments );

        }

    }

    // generate indices

    for ( j = 1; j <= tubularSegments; j ++ ) {

        for ( i = 1; i <= radialSegments; i ++ ) {

            // indices

            var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
            var b = ( radialSegments + 1 ) * j + ( i - 1 );
            var c = ( radialSegments + 1 ) * j + i;
            var d = ( radialSegments + 1 ) * ( j - 1 ) + i;

            // faces

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    // this function calculates the current position on the torus curve

    function calculatePositionOnCurve( u, p, q, radius, position ) {

        var cu = Math.cos( u );
        var su = Math.sin( u );
        var quOverP = q / p * u;
        var cs = Math.cos( quOverP );

        position.x = radius * ( 2 + cs ) * 0.5 * cu;
        position.y = radius * ( 2 + cs ) * su * 0.5;
        position.z = radius * Math.sin( quOverP ) * 0.5;

    }

}

TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;

/**
 * @author oosmoxiecode
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

// TorusGeometry

function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {

    Geometry.call( this );

    this.type = 'TorusGeometry';

    this.parameters = {
        radius: radius,
        tube: tube,
        radialSegments: radialSegments,
        tubularSegments: tubularSegments,
        arc: arc
    };

    this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
    this.mergeVertices();

}

TorusGeometry.prototype = Object.create( Geometry.prototype );
TorusGeometry.prototype.constructor = TorusGeometry;

// TorusBufferGeometry

function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {

    BufferGeometry.call( this );

    this.type = 'TorusBufferGeometry';

    this.parameters = {
        radius: radius,
        tube: tube,
        radialSegments: radialSegments,
        tubularSegments: tubularSegments,
        arc: arc
    };

    radius = radius || 100;
    tube = tube || 40;
    radialSegments = Math.floor( radialSegments ) || 8;
    tubularSegments = Math.floor( tubularSegments ) || 6;
    arc = arc || Math.PI * 2;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var center = new Vector3();
    var vertex = new Vector3();
    var normal = new Vector3();

    var j, i;

    // generate vertices, normals and uvs

    for ( j = 0; j <= radialSegments; j ++ ) {

        for ( i = 0; i <= tubularSegments; i ++ ) {

            var u = i / tubularSegments * arc;
            var v = j / radialSegments * Math.PI * 2;

            // vertex

            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 );

            vertices.push( vertex.x, vertex.y, vertex.z );

            // normal

            center.x = radius * Math.cos( u );
            center.y = radius * Math.sin( u );
            normal.subVectors( vertex, center ).normalize();

            normals.push( normal.x, normal.y, normal.z );

            // uv

            uvs.push( i / tubularSegments );
            uvs.push( j / radialSegments );

        }

    }

    // generate indices

    for ( j = 1; j <= radialSegments; j ++ ) {

        for ( i = 1; i <= tubularSegments; i ++ ) {

            // indices

            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;

            // faces

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 */

var ShapeUtils = {

    // calculate area of the contour polygon

    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;

    },

    triangulate: ( function () {

        /**
         * 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 snip( 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 ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) 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 >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false;

            }

            return true;

        }

        // takes in an contour array and returns

        return function triangulate( 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 ( ShapeUtils.area( contour ) > 0.0 ) {

                for ( v = 0; v < n; v ++ ) verts[ v ] = v;

            } else {

                for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;

            }

            var nv = n;

            /*  remove nv - 2 vertices, creating 1 triangle every time */

            var count = 2 * nv;   /* error detection */

            for ( v = nv - 1; nv > 2; ) {

                /* if we loop, it is probably a non-simple polygon */

                if ( ( count -- ) <= 0 ) {

                    //** Triangulate: ERROR - probable bad polygon!

                    //throw ( "Warning, unable to triangulate polygon!" );
                    //return null;
                    // Sometimes warning is fine, especially polygons are triangulated in reverse.
                    console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' );

                    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;

        }

    } )(),

    triangulateShape: function ( contour, holes ) {

        function removeDupEndPts(points) {

            var l = points.length;

            if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {

                points.pop();

            }

        }

        removeDupEndPts( contour );
        holes.forEach( removeDupEndPts );

        function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {

            // inOtherPt needs to be collinear 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 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 ) > Number.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 collinear
                if ( ( perpSeg1 !== 0 ) ||
                     ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) )             return [];

                // they are collinear or degenerate
                var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) );    // segment1 is just a point?
                var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) );    // segment2 is 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

            // 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 ) > Number.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 ) {

                console.warn( "THREE.ShapeUtils: Duplicate point", key, i );

            }

            allPointsMap[ key ] = i;

        }

        // remove holes by cutting paths to holes and adding them to the shape
        var shapeWithoutHoles = removeHoles( contour, holes );

        var triangles = ShapeUtils.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 ShapeUtils.area( pts ) < 0;

    }

};

/**
 * @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 segments 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.Curve> // curve to extrude shape along
 *  frames: <Object> // containing arrays of tangents, normals, binormals
 *
 *  UVGenerator: <Object> // object that provides UV generator functions
 *
 * }
 */

// ExtrudeGeometry

function ExtrudeGeometry( shapes, options ) {

    Geometry.call( this );

    this.type = 'ExtrudeGeometry';

    this.parameters = {
        shapes: shapes,
        options: options
    };

    this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
    this.mergeVertices();

}

ExtrudeGeometry.prototype = Object.create( Geometry.prototype );
ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;

// ExtrudeBufferGeometry

function ExtrudeBufferGeometry( shapes, options ) {

    if ( typeof ( shapes ) === "undefined" ) {

        return;

    }

    BufferGeometry.call( this );

    this.type = 'ExtrudeBufferGeometry';

    shapes = Array.isArray( shapes ) ? shapes : [ shapes ];

    this.addShapeList( shapes, options );

    this.computeVertexNormals();

    // 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 ) );

}

ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;

ExtrudeBufferGeometry.prototype.getArrays = function () {

    var positionAttribute = this.getAttribute( "position" );
    var verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : [];

    var uvAttribute = this.getAttribute( "uv" );
    var uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : [];

    var IndexAttribute = this.index;
    var indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : [];

    return {
        position: verticesArray,
        uv: uvArray,
        index: indicesArray
    };

};

ExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) {

    var sl = shapes.length;
    options.arrays = this.getArrays();

    for ( var s = 0; s < sl; s ++ ) {

        var shape = shapes[ s ];
        this.addShape( shape, options );

    }

    this.setIndex( options.arrays.index );
    this.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );

};

ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) {

    var arrays = options.arrays ? options.arrays : this.getArrays();
    var verticesArray = arrays.position;
    var indicesArray = arrays.index;
    var uvArray = arrays.uv;

    var placeholder = [];


    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;

    // Use default WorldUVGenerator if no UV generators are specified.
    var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : 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

        // TODO1 - have a .isClosed in spline?

        splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false );

        // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);

        binormal = new Vector3();
        normal = new Vector3();
        position2 = new Vector3();

    }

    // Safeguards if bevels are not enabled

    if ( ! bevelEnabled ) {

        bevelSegments = 0;
        bevelThickness = 0;
        bevelSize = 0;

    }

    // Variables initialization

    var ahole, h, hl; // looping of holes
    var scope = this;

    var shapePoints = shape.extractPoints( curveSegments );

    var vertices = shapePoints.shape;
    var holes = shapePoints.holes;

    var reverse = ! ShapeUtils.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 ( ShapeUtils.isClockWise( ahole ) ) {

                holes[ h ] = ahole.reverse();

            }

        }

    }


    var faces = ShapeUtils.triangulateShape( vertices, holes );

    /* Vertices */

    var contour = vertices; // vertices has all points but contour has only points of circumference

    for ( h = 0, hl = holes.length; h < hl; h ++ ) {

        ahole = holes[ h ];

        vertices = vertices.concat( ahole );

    }


    function scalePt2( pt, vec, size ) {

        if ( ! vec ) console.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 ) {

        // computes for inPt the corresponding point inPt' on a new contour
        //   shifted 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; // 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 collinear edges
        var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );

        if ( Math.abs( collinear0 ) > Number.EPSILON ) {

            // not collinear

            // 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 Vector2( v_trans_x, v_trans_y );

            } else {

                shrink_by = Math.sqrt( v_trans_lensq / 2 );

            }

        } else {

            // handle special case of collinear edges

            var direction_eq = false; // assumes: opposite
            if ( v_prev_x > Number.EPSILON ) {

                if ( v_next_x > Number.EPSILON ) {

                    direction_eq = true;

                }

            } else {

                if ( v_prev_x < - Number.EPSILON ) {

                    if ( v_next_x < - Number.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 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 * Math.cos( 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, - 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 * Math.cos( 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() {

        var start = verticesArray.length/3;

        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 );

            }

        }

        scope.addGroup( start, verticesArray.length/3 -start, options.material !== undefined ? options.material : 0);

    }

    // Create faces for the z-sides of the shape

    function buildSideFaces() {

        var start = verticesArray.length/3;
        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;

        }


        scope.addGroup( start, verticesArray.length/3 -start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1);


    }

    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 ) {

        placeholder.push( x );
        placeholder.push( y );
        placeholder.push( z );

    }


    function f3( a, b, c ) {

        addVertex( a );
        addVertex( b );
        addVertex( c );

        var nextIndex = verticesArray.length / 3;
        var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );

        addUV( uvs[ 0 ] );
        addUV( uvs[ 1 ] );
        addUV( uvs[ 2 ] );

    }

    function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {

        addVertex( a );
        addVertex( b );
        addVertex( d );

        addVertex( b );
        addVertex( c );
        addVertex( d );


        var nextIndex = verticesArray.length / 3;
        var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );

        addUV( uvs[ 0 ] );
        addUV( uvs[ 1 ] );
        addUV( uvs[ 3 ] );

        addUV( uvs[ 1 ] );
        addUV( uvs[ 2 ] );
        addUV( uvs[ 3 ] );

    }

    function addVertex( index ) {

        indicesArray.push( verticesArray.length / 3 );
        verticesArray.push( placeholder[ index * 3 + 0 ] );
        verticesArray.push( placeholder[ index * 3 + 1 ] );
        verticesArray.push( placeholder[ index * 3 + 2 ] );

    }


    function addUV( vector2 ) {

        uvArray.push( vector2.x );
        uvArray.push( vector2.y );

    }

    if ( ! options.arrays ) {

        this.setIndex( indicesArray );
        this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
        this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );

    }

};

ExtrudeGeometry.WorldUVGenerator = {

    generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {

        var a_x = vertices[ indexA * 3 ];
        var a_y = vertices[ indexA * 3 + 1 ];
        var b_x = vertices[ indexB * 3 ];
        var b_y = vertices[ indexB * 3 + 1 ];
        var c_x = vertices[ indexC * 3 ];
        var c_y = vertices[ indexC * 3 + 1 ];

        return [
            new Vector2( a_x, a_y ),
            new Vector2( b_x, b_y ),
            new Vector2( c_x, c_y )
        ];

    },

    generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {

        var a_x = vertices[ indexA * 3 ];
        var a_y = vertices[ indexA * 3 + 1 ];
        var a_z = vertices[ indexA * 3 + 2 ];
        var b_x = vertices[ indexB * 3 ];
        var b_y = vertices[ indexB * 3 + 1 ];
        var b_z = vertices[ indexB * 3 + 2 ];
        var c_x = vertices[ indexC * 3 ];
        var c_y = vertices[ indexC * 3 + 1 ];
        var c_z = vertices[ indexC * 3 + 2 ];
        var d_x = vertices[ indexD * 3 ];
        var d_y = vertices[ indexD * 3 + 1 ];
        var d_z = vertices[ indexD * 3 + 2 ];

        if ( Math.abs( a_y - b_y ) < 0.01 ) {

            return [
                new Vector2( a_x, 1 - a_z ),
                new Vector2( b_x, 1 - b_z ),
                new Vector2( c_x, 1 - c_z ),
                new Vector2( d_x, 1 - d_z )
            ];

        } else {

            return [
                new Vector2( a_y, 1 - a_z ),
                new Vector2( b_y, 1 - b_z ),
                new Vector2( c_y, 1 - c_z ),
                new Vector2( d_y, 1 - d_z )
            ];

        }

    }
};

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * @author alteredq / http://alteredqualia.com/
 *
 * Text = 3D Text
 *
 * parameters = {
 *  font: <THREE.Font>, // font
 *
 *  size: <float>, // size of the text
 *  height: <float>, // thickness to extrude text
 *  curveSegments: <int>, // number of points on the curves
 *
 *  bevelEnabled: <bool>, // turn on bevel
 *  bevelThickness: <float>, // how deep into text bevel goes
 *  bevelSize: <float> // how far from text outline is bevel
 * }
 */

// TextGeometry

function TextGeometry(  text, parameters ) {

    Geometry.call( this );

    this.type = 'TextGeometry';

    this.parameters = {
        text: text,
        parameters: parameters
    };

    this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
    this.mergeVertices();

}

TextGeometry.prototype = Object.create( Geometry.prototype );
TextGeometry.prototype.constructor = TextGeometry;

// TextBufferGeometry

function TextBufferGeometry( text, parameters ) {

    parameters = parameters || {};

    var font = parameters.font;

    if ( ! ( font && font.isFont ) ) {

        console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
        return new Geometry();

    }

    var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );

    // 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;

    ExtrudeBufferGeometry.call( this, shapes, parameters );

    this.type = 'TextBufferGeometry';

}

TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );
TextBufferGeometry.prototype.constructor = TextBufferGeometry;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author benaadams / https://twitter.com/ben_a_adams
 * @author Mugen87 / https://github.com/Mugen87
 */

// SphereGeometry

function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {

    Geometry.call( this );

    this.type = 'SphereGeometry';

    this.parameters = {
        radius: radius,
        widthSegments: widthSegments,
        heightSegments: heightSegments,
        phiStart: phiStart,
        phiLength: phiLength,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
    this.mergeVertices();

}

SphereGeometry.prototype = Object.create( Geometry.prototype );
SphereGeometry.prototype.constructor = SphereGeometry;

// SphereBufferGeometry

function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {

    BufferGeometry.call( this );

    this.type = 'SphereBufferGeometry';

    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 thetaEnd = thetaStart + thetaLength;

    var ix, iy;

    var index = 0;
    var grid = [];

    var vertex = new Vector3();
    var normal = new Vector3();

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // generate vertices, normals and uvs

    for ( iy = 0; iy <= heightSegments; iy ++ ) {

        var verticesRow = [];

        var v = iy / heightSegments;

        for ( ix = 0; ix <= widthSegments; ix ++ ) {

            var u = ix / widthSegments;

            // vertex

            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 );

            vertices.push( vertex.x, vertex.y, vertex.z );

            // normal

            normal.set( vertex.x, vertex.y, vertex.z ).normalize();
            normals.push( normal.x, normal.y, normal.z );

            // uv

            uvs.push( u, 1 - v );

            verticesRow.push( index ++ );

        }

        grid.push( verticesRow );

    }

    // indices

    for ( iy = 0; iy < heightSegments; iy ++ ) {

        for ( ix = 0; ix < widthSegments; ix ++ ) {

            var a = grid[ iy ][ ix + 1 ];
            var b = grid[ iy ][ ix ];
            var c = grid[ iy + 1 ][ ix ];
            var d = grid[ iy + 1 ][ ix + 1 ];

            if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
            if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;

/**
 * @author Kaleb Murphy
 * @author Mugen87 / https://github.com/Mugen87
 */

// RingGeometry

function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {

    Geometry.call( this );

    this.type = 'RingGeometry';

    this.parameters = {
        innerRadius: innerRadius,
        outerRadius: outerRadius,
        thetaSegments: thetaSegments,
        phiSegments: phiSegments,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
    this.mergeVertices();

}

RingGeometry.prototype = Object.create( Geometry.prototype );
RingGeometry.prototype.constructor = RingGeometry;

// RingBufferGeometry

function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {

    BufferGeometry.call( this );

    this.type = 'RingBufferGeometry';

    this.parameters = {
        innerRadius: innerRadius,
        outerRadius: outerRadius,
        thetaSegments: thetaSegments,
        phiSegments: phiSegments,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    innerRadius = innerRadius || 20;
    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 ) : 1;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // some helper variables

    var segment;
    var radius = innerRadius;
    var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
    var vertex = new Vector3();
    var uv = new Vector2();
    var j, i;

    // generate vertices, normals and uvs

    for ( j = 0; j <= phiSegments; j ++ ) {

        for ( i = 0; i <= thetaSegments; i ++ ) {

            // values are generate from the inside of the ring to the outside

            segment = thetaStart + i / thetaSegments * thetaLength;

            // vertex

            vertex.x = radius * Math.cos( segment );
            vertex.y = radius * Math.sin( segment );

            vertices.push( vertex.x, vertex.y, vertex.z );

            // normal

            normals.push( 0, 0, 1 );

            // uv

            uv.x = ( vertex.x / outerRadius + 1 ) / 2;
            uv.y = ( vertex.y / outerRadius + 1 ) / 2;

            uvs.push( uv.x, uv.y );

        }

        // increase the radius for next row of vertices

        radius += radiusStep;

    }

    // indices

    for ( j = 0; j < phiSegments; j ++ ) {

        var thetaSegmentLevel = j * ( thetaSegments + 1 );

        for ( i = 0; i < thetaSegments; i ++ ) {

            segment = i + thetaSegmentLevel;

            var a = segment;
            var b = segment + thetaSegments + 1;
            var c = segment + thetaSegments + 2;
            var d = segment + 1;

            // faces

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
RingBufferGeometry.prototype.constructor = RingBufferGeometry;

/**
 * @author astrodud / http://astrodud.isgreat.org/
 * @author zz85 / https://github.com/zz85
 * @author bhouston / http://clara.io
 * @author Mugen87 / https://github.com/Mugen87
 */

// LatheGeometry

function LatheGeometry( points, segments, phiStart, phiLength ) {

    Geometry.call( this );

    this.type = 'LatheGeometry';

    this.parameters = {
        points: points,
        segments: segments,
        phiStart: phiStart,
        phiLength: phiLength
    };

    this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
    this.mergeVertices();

}

LatheGeometry.prototype = Object.create( Geometry.prototype );
LatheGeometry.prototype.constructor = LatheGeometry;

// LatheBufferGeometry

function LatheBufferGeometry( points, segments, phiStart, phiLength ) {

    BufferGeometry.call( this );

    this.type = 'LatheBufferGeometry';

    this.parameters = {
        points: points,
        segments: segments,
        phiStart: phiStart,
        phiLength: phiLength
    };

    segments = Math.floor( segments ) || 12;
    phiStart = phiStart || 0;
    phiLength = phiLength || Math.PI * 2;

    // clamp phiLength so it's in range of [ 0, 2PI ]

    phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );


    // buffers

    var indices = [];
    var vertices = [];
    var uvs = [];

    // helper variables

    var base;
    var inverseSegments = 1.0 / segments;
    var vertex = new Vector3();
    var uv = new Vector2();
    var i, j;

    // generate vertices and uvs

    for ( i = 0; i <= segments; i ++ ) {

        var phi = phiStart + i * inverseSegments * phiLength;

        var sin = Math.sin( phi );
        var cos = Math.cos( phi );

        for ( j = 0; j <= ( points.length - 1 ); j ++ ) {

            // vertex

            vertex.x = points[ j ].x * sin;
            vertex.y = points[ j ].y;
            vertex.z = points[ j ].x * cos;

            vertices.push( vertex.x, vertex.y, vertex.z );

            // uv

            uv.x = i / segments;
            uv.y = j / ( points.length - 1 );

            uvs.push( uv.x, uv.y );


        }

    }

    // indices

    for ( i = 0; i < segments; i ++ ) {

        for ( j = 0; j < ( points.length - 1 ); j ++ ) {

            base = j + i * points.length;

            var a = base;
            var b = base + points.length;
            var c = base + points.length + 1;
            var d = base + 1;

            // faces

            indices.push( a, b, d );
            indices.push( b, c, d );

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    // generate normals

    this.computeVertexNormals();

    // if the geometry is closed, we need to average the normals along the seam.
    // because the corresponding vertices are identical (but still have different UVs).

    if ( phiLength === Math.PI * 2 ) {

        var normals = this.attributes.normal.array;
        var n1 = new Vector3();
        var n2 = new Vector3();
        var n = new Vector3();

        // this is the buffer offset for the last line of vertices

        base = segments * points.length * 3;

        for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {

            // select the normal of the vertex in the first line

            n1.x = normals[ j + 0 ];
            n1.y = normals[ j + 1 ];
            n1.z = normals[ j + 2 ];

            // select the normal of the vertex in the last line

            n2.x = normals[ base + j + 0 ];
            n2.y = normals[ base + j + 1 ];
            n2.z = normals[ base + j + 2 ];

            // average normals

            n.addVectors( n1, n2 ).normalize();

            // assign the new values to both normals

            normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
            normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
            normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;

        }

    }

}

LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;

/**
 * @author jonobr1 / http://jonobr1.com
 * @author Mugen87 / https://github.com/Mugen87
 */

// ShapeGeometry

function ShapeGeometry( shapes, curveSegments ) {

    Geometry.call( this );

    this.type = 'ShapeGeometry';

    if ( typeof curveSegments === 'object' ) {

        console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );

        curveSegments = curveSegments.curveSegments;

    }

    this.parameters = {
        shapes: shapes,
        curveSegments: curveSegments
    };

    this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
    this.mergeVertices();

}

ShapeGeometry.prototype = Object.create( Geometry.prototype );
ShapeGeometry.prototype.constructor = ShapeGeometry;

// ShapeBufferGeometry

function ShapeBufferGeometry( shapes, curveSegments ) {

    BufferGeometry.call( this );

    this.type = 'ShapeBufferGeometry';

    this.parameters = {
        shapes: shapes,
        curveSegments: curveSegments
    };

    curveSegments = curveSegments || 12;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var groupStart = 0;
    var groupCount = 0;

    // allow single and array values for "shapes" parameter

    if ( Array.isArray( shapes ) === false ) {

        addShape( shapes );

    } else {

        for ( var i = 0; i < shapes.length; i ++ ) {

            addShape( shapes[ i ] );

            this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support

            groupStart += groupCount;
            groupCount = 0;

        }

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );


    // helper functions

    function addShape( shape ) {

        var i, l, shapeHole;

        var indexOffset = vertices.length / 3;
        var points = shape.extractPoints( curveSegments );

        var shapeVertices = points.shape;
        var shapeHoles = points.holes;

        // check direction of vertices

        if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {

            shapeVertices = shapeVertices.reverse();

            // also check if holes are in the opposite direction

            for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {

                shapeHole = shapeHoles[ i ];

                if ( ShapeUtils.isClockWise( shapeHole ) === true ) {

                    shapeHoles[ i ] = shapeHole.reverse();

                }

            }

        }

        var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );

        // join vertices of inner and outer paths to a single array

        for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {

            shapeHole = shapeHoles[ i ];
            shapeVertices = shapeVertices.concat( shapeHole );

        }

        // vertices, normals, uvs

        for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {

            var vertex = shapeVertices[ i ];

            vertices.push( vertex.x, vertex.y, 0 );
            normals.push( 0, 0, 1 );
            uvs.push( vertex.x, vertex.y ); // world uvs

        }

        // incides

        for ( i = 0, l = faces.length; i < l; i ++ ) {

            var face = faces[ i ];

            var a = face[ 0 ] + indexOffset;
            var b = face[ 1 ] + indexOffset;
            var c = face[ 2 ] + indexOffset;

            indices.push( a, b, c );
            groupCount += 3;

        }

    }

}

ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;

/**
 * @author WestLangley / http://github.com/WestLangley
 * @author Mugen87 / https://github.com/Mugen87
 */

function EdgesGeometry( geometry, thresholdAngle ) {

    BufferGeometry.call( this );

    this.type = 'EdgesGeometry';

    this.parameters = {
        thresholdAngle: thresholdAngle
    };

    thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;

    // buffer

    var vertices = [];

    // helper variables

    var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );
    var edge = [ 0, 0 ], edges = {}, edge1, edge2;
    var key, keys = [ 'a', 'b', 'c' ];

    // prepare source geometry

    var geometry2;

    if ( geometry.isBufferGeometry ) {

        geometry2 = new Geometry();
        geometry2.fromBufferGeometry( geometry );

    } else {

        geometry2 = geometry.clone();

    }

    geometry2.mergeVertices();
    geometry2.computeFaceNormals();

    var sourceVertices = geometry2.vertices;
    var faces = geometry2.faces;

    // now create a data structure where each entry represents an edge with its adjoining faces

    for ( var i = 0, l = faces.length; i < l; i ++ ) {

        var face = faces[ i ];

        for ( var j = 0; j < 3; j ++ ) {

            edge1 = face[ keys[ j ] ];
            edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
            edge[ 0 ] = Math.min( edge1, edge2 );
            edge[ 1 ] = Math.max( edge1, edge2 );

            key = edge[ 0 ] + ',' + edge[ 1 ];

            if ( edges[ key ] === undefined ) {

                edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };

            } else {

                edges[ key ].face2 = i;

            }

        }

    }

    // generate vertices

    for ( key in edges ) {

        var e = edges[ key ];

        // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.

        if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {

            var vertex = sourceVertices[ e.index1 ];
            vertices.push( vertex.x, vertex.y, vertex.z );

            vertex = sourceVertices[ e.index2 ];
            vertices.push( vertex.x, vertex.y, vertex.z );

        }

    }

    // build geometry

    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );

}

EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
EdgesGeometry.prototype.constructor = EdgesGeometry;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

// CylinderGeometry

function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

    Geometry.call( this );

    this.type = 'CylinderGeometry';

    this.parameters = {
        radiusTop: radiusTop,
        radiusBottom: radiusBottom,
        height: height,
        radialSegments: radialSegments,
        heightSegments: heightSegments,
        openEnded: openEnded,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
    this.mergeVertices();

}

CylinderGeometry.prototype = Object.create( Geometry.prototype );
CylinderGeometry.prototype.constructor = CylinderGeometry;

// CylinderBufferGeometry

function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

    BufferGeometry.call( this );

    this.type = 'CylinderBufferGeometry';

    this.parameters = {
        radiusTop: radiusTop,
        radiusBottom: radiusBottom,
        height: height,
        radialSegments: radialSegments,
        heightSegments: heightSegments,
        openEnded: openEnded,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    var scope = this;

    radiusTop = radiusTop !== undefined ? radiusTop : 20;
    radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
    height = height !== undefined ? height : 100;

    radialSegments = Math.floor( radialSegments ) || 8;
    heightSegments = Math.floor( heightSegments ) || 1;

    openEnded = openEnded !== undefined ? openEnded : false;
    thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
    thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var index = 0;
    var indexArray = [];
    var halfHeight = height / 2;
    var groupStart = 0;

    // generate geometry

    generateTorso();

    if ( openEnded === false ) {

        if ( radiusTop > 0 ) generateCap( true );
        if ( radiusBottom > 0 ) generateCap( false );

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    function generateTorso() {

        var x, y;
        var normal = new Vector3();
        var vertex = new Vector3();

        var groupCount = 0;

        // this will be used to calculate the normal
        var slope = ( radiusBottom - radiusTop ) / height;

        // generate vertices, normals and uvs

        for ( y = 0; y <= heightSegments; y ++ ) {

            var indexRow = [];

            var v = y / heightSegments;

            // calculate the radius of the current row

            var radius = v * ( radiusBottom - radiusTop ) + radiusTop;

            for ( x = 0; x <= radialSegments; x ++ ) {

                var u = x / radialSegments;

                var theta = u * thetaLength + thetaStart;

                var sinTheta = Math.sin( theta );
                var cosTheta = Math.cos( theta );

                // vertex

                vertex.x = radius * sinTheta;
                vertex.y = - v * height + halfHeight;
                vertex.z = radius * cosTheta;
                vertices.push( vertex.x, vertex.y, vertex.z );

                // normal

                normal.set( sinTheta, slope, cosTheta ).normalize();
                normals.push( normal.x, normal.y, normal.z );

                // uv

                uvs.push( u, 1 - v );

                // save index of vertex in respective row

                indexRow.push( index ++ );

            }

            // now save vertices of the row in our index array

            indexArray.push( indexRow );

        }

        // generate indices

        for ( x = 0; x < radialSegments; x ++ ) {

            for ( y = 0; y < heightSegments; y ++ ) {

                // we use the index array to access the correct indices

                var a = indexArray[ y ][ x ];
                var b = indexArray[ y + 1 ][ x ];
                var c = indexArray[ y + 1 ][ x + 1 ];
                var d = indexArray[ y ][ x + 1 ];

                // faces

                indices.push( a, b, d );
                indices.push( b, c, d );

                // update group counter

                groupCount += 6;

            }

        }

        // add a group to the geometry. this will ensure multi material support

        scope.addGroup( groupStart, groupCount, 0 );

        // calculate new start value for groups

        groupStart += groupCount;

    }

    function generateCap( top ) {

        var x, centerIndexStart, centerIndexEnd;

        var uv = new Vector2();
        var vertex = new Vector3();

        var groupCount = 0;

        var radius = ( top === true ) ? radiusTop : radiusBottom;
        var sign = ( top === true ) ? 1 : - 1;

        // save the index of the first center vertex
        centerIndexStart = index;

        // first we generate the center vertex data of the cap.
        // because the geometry needs one set of uvs per face,
        // we must generate a center vertex per face/segment

        for ( x = 1; x <= radialSegments; x ++ ) {

            // vertex

            vertices.push( 0, halfHeight * sign, 0 );

            // normal

            normals.push( 0, sign, 0 );

            // uv

            uvs.push( 0.5, 0.5 );

            // increase index

            index ++;

        }

        // save the index of the last center vertex

        centerIndexEnd = index;

        // now we generate the surrounding vertices, normals and uvs

        for ( x = 0; x <= radialSegments; x ++ ) {

            var u = x / radialSegments;
            var theta = u * thetaLength + thetaStart;

            var cosTheta = Math.cos( theta );
            var sinTheta = Math.sin( theta );

            // vertex

            vertex.x = radius * sinTheta;
            vertex.y = halfHeight * sign;
            vertex.z = radius * cosTheta;
            vertices.push( vertex.x, vertex.y, vertex.z );

            // normal

            normals.push( 0, sign, 0 );

            // uv

            uv.x = ( cosTheta * 0.5 ) + 0.5;
            uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
            uvs.push( uv.x, uv.y );

            // increase index

            index ++;

        }

        // generate indices

        for ( x = 0; x < radialSegments; x ++ ) {

            var c = centerIndexStart + x;
            var i = centerIndexEnd + x;

            if ( top === true ) {

                // face top

                indices.push( i, i + 1, c );

            } else {

                // face bottom

                indices.push( i + 1, i, c );

            }

            groupCount += 3;

        }

        // add a group to the geometry. this will ensure multi material support

        scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );

        // calculate new start value for groups

        groupStart += groupCount;

    }

}

CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;

/**
 * @author abelnation / http://github.com/abelnation
 */

// ConeGeometry

function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

    CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );

    this.type = 'ConeGeometry';

    this.parameters = {
        radius: radius,
        height: height,
        radialSegments: radialSegments,
        heightSegments: heightSegments,
        openEnded: openEnded,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

}

ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
ConeGeometry.prototype.constructor = ConeGeometry;

// ConeBufferGeometry

function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

    CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );

    this.type = 'ConeBufferGeometry';

    this.parameters = {
        radius: radius,
        height: height,
        radialSegments: radialSegments,
        heightSegments: heightSegments,
        openEnded: openEnded,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

}

ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 * @author Mugen87 / https://github.com/Mugen87
 * @author hughes
 */

// CircleGeometry

function CircleGeometry( radius, segments, thetaStart, thetaLength ) {

    Geometry.call( this );

    this.type = 'CircleGeometry';

    this.parameters = {
        radius: radius,
        segments: segments,
        thetaStart: thetaStart,
        thetaLength: thetaLength
    };

    this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
    this.mergeVertices();

}

CircleGeometry.prototype = Object.create( Geometry.prototype );
CircleGeometry.prototype.constructor = CircleGeometry;

// CircleBufferGeometry

function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {

    BufferGeometry.call( this );

    this.type = 'CircleBufferGeometry';

    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;

    // buffers

    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];

    // helper variables

    var i, s;
    var vertex = new Vector3();
    var uv = new Vector2();

    // center point

    vertices.push( 0, 0, 0 );
    normals.push( 0, 0, 1 );
    uvs.push( 0.5, 0.5 );

    for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {

        var segment = thetaStart + s / segments * thetaLength;

        // vertex

        vertex.x = radius * Math.cos( segment );
        vertex.y = radius * Math.sin( segment );

        vertices.push( vertex.x, vertex.y, vertex.z );

        // normal

        normals.push( 0, 0, 1 );

        // uvs

        uv.x = ( vertices[ i ] / radius + 1 ) / 2;
        uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;

        uvs.push( uv.x, uv.y );

    }

    // indices

    for ( i = 1; i <= segments; i ++ ) {

        indices.push( i, i + 1, 0 );

    }

    // build geometry

    this.setIndex( indices );
    this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

}

CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;



var Geometries = Object.freeze({
    WireframeGeometry: WireframeGeometry,
    ParametricGeometry: ParametricGeometry,
    ParametricBufferGeometry: ParametricBufferGeometry,
    TetrahedronGeometry: TetrahedronGeometry,
    TetrahedronBufferGeometry: TetrahedronBufferGeometry,
    OctahedronGeometry: OctahedronGeometry,
    OctahedronBufferGeometry: OctahedronBufferGeometry,
    IcosahedronGeometry: IcosahedronGeometry,
    IcosahedronBufferGeometry: IcosahedronBufferGeometry,
    DodecahedronGeometry: DodecahedronGeometry,
    DodecahedronBufferGeometry: DodecahedronBufferGeometry,
    PolyhedronGeometry: PolyhedronGeometry,
    PolyhedronBufferGeometry: PolyhedronBufferGeometry,
    TubeGeometry: TubeGeometry,
    TubeBufferGeometry: TubeBufferGeometry,
    TorusKnotGeometry: TorusKnotGeometry,
    TorusKnotBufferGeometry: TorusKnotBufferGeometry,
    TorusGeometry: TorusGeometry,
    TorusBufferGeometry: TorusBufferGeometry,
    TextGeometry: TextGeometry,
    TextBufferGeometry: TextBufferGeometry,
    SphereGeometry: SphereGeometry,
    SphereBufferGeometry: SphereBufferGeometry,
    RingGeometry: RingGeometry,
    RingBufferGeometry: RingBufferGeometry,
    PlaneGeometry: PlaneGeometry,
    PlaneBufferGeometry: PlaneBufferGeometry,
    LatheGeometry: LatheGeometry,
    LatheBufferGeometry: LatheBufferGeometry,
    ShapeGeometry: ShapeGeometry,
    ShapeBufferGeometry: ShapeBufferGeometry,
    ExtrudeGeometry: ExtrudeGeometry,
    ExtrudeBufferGeometry: ExtrudeBufferGeometry,
    EdgesGeometry: EdgesGeometry,
    ConeGeometry: ConeGeometry,
    ConeBufferGeometry: ConeBufferGeometry,
    CylinderGeometry: CylinderGeometry,
    CylinderBufferGeometry: CylinderBufferGeometry,
    CircleGeometry: CircleGeometry,
    CircleBufferGeometry: CircleBufferGeometry,
    BoxGeometry: BoxGeometry,
    BoxBufferGeometry: BoxBufferGeometry
});

/**
 * @author mrdoob / http://mrdoob.com/
 *
 * parameters = {
 *  opacity: <float>
 * }
 */

function ShadowMaterial( parameters ) {

    ShaderMaterial.call( this, {
        uniforms: UniformsUtils.merge( [
            UniformsLib.lights,
            {
                opacity: { value: 1.0 }
            }
        ] ),
        vertexShader: ShaderChunk[ 'shadow_vert' ],
        fragmentShader: ShaderChunk[ 'shadow_frag' ]
    } );

    this.lights = true;
    this.transparent = true;

    Object.defineProperties( this, {
        opacity: {
            enumerable: true,
            get: function () {
                return this.uniforms.opacity.value;
            },
            set: function ( value ) {
                this.uniforms.opacity.value = value;
            }
        }
    } );

    this.setValues( parameters );

}

ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype );
ShadowMaterial.prototype.constructor = ShadowMaterial;

ShadowMaterial.prototype.isShadowMaterial = true;

/**
 * @author mrdoob / http://mrdoob.com/
 */

function RawShaderMaterial( parameters ) {

    ShaderMaterial.call( this, parameters );

    this.type = 'RawShaderMaterial';

}

RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
RawShaderMaterial.prototype.constructor = RawShaderMaterial;

RawShaderMaterial.prototype.isRawShaderMaterial = true;

/**
 * @author WestLangley / http://github.com/WestLangley
 *
 * parameters = {
 *  color: <hex>,
 *  roughness: <float>,
 *  metalness: <float>,
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *  lightMapIntensity: <float>
 *
 *  aoMap: new THREE.Texture( <Image> ),
 *  aoMapIntensity: <float>
 *
 *  emissive: <hex>,
 *  emissiveIntensity: <float>
 *  emissiveMap: new THREE.Texture( <Image> ),
 *
 *  bumpMap: new THREE.Texture( <Image> ),
 *  bumpScale: <float>,
 *
 *  normalMap: new THREE.Texture( <Image> ),
 *  normalScale: <Vector2>,
 *
 *  displacementMap: new THREE.Texture( <Image> ),
 *  displacementScale: <float>,
 *  displacementBias: <float>,
 *
 *  roughnessMap: new THREE.Texture( <Image> ),
 *
 *  metalnessMap: new THREE.Texture( <Image> ),
 *
 *  alphaMap: new THREE.Texture( <Image> ),
 *
 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
 *  envMapIntensity: <float>
 *
 *  refractionRatio: <float>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>
 * }
 */

function MeshStandardMaterial( parameters ) {

    Material.call( this );

    this.defines = { 'STANDARD': '' };

    this.type = 'MeshStandardMaterial';

    this.color = new Color( 0xffffff ); // diffuse
    this.roughness = 0.5;
    this.metalness = 0.5;

    this.map = null;

    this.lightMap = null;
    this.lightMapIntensity = 1.0;

    this.aoMap = null;
    this.aoMapIntensity = 1.0;

    this.emissive = new Color( 0x000000 );
    this.emissiveIntensity = 1.0;
    this.emissiveMap = null;

    this.bumpMap = null;
    this.bumpScale = 1;

    this.normalMap = null;
    this.normalScale = new Vector2( 1, 1 );

    this.displacementMap = null;
    this.displacementScale = 1;
    this.displacementBias = 0;

    this.roughnessMap = null;

    this.metalnessMap = null;

    this.alphaMap = null;

    this.envMap = null;
    this.envMapIntensity = 1.0;

    this.refractionRatio = 0.98;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

}

MeshStandardMaterial.prototype = Object.create( Material.prototype );
MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;

MeshStandardMaterial.prototype.isMeshStandardMaterial = true;

MeshStandardMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.defines = { 'STANDARD': '' };

    this.color.copy( source.color );
    this.roughness = source.roughness;
    this.metalness = source.metalness;

    this.map = source.map;

    this.lightMap = source.lightMap;
    this.lightMapIntensity = source.lightMapIntensity;

    this.aoMap = source.aoMap;
    this.aoMapIntensity = source.aoMapIntensity;

    this.emissive.copy( source.emissive );
    this.emissiveMap = source.emissiveMap;
    this.emissiveIntensity = source.emissiveIntensity;

    this.bumpMap = source.bumpMap;
    this.bumpScale = source.bumpScale;

    this.normalMap = source.normalMap;
    this.normalScale.copy( source.normalScale );

    this.displacementMap = source.displacementMap;
    this.displacementScale = source.displacementScale;
    this.displacementBias = source.displacementBias;

    this.roughnessMap = source.roughnessMap;

    this.metalnessMap = source.metalnessMap;

    this.alphaMap = source.alphaMap;

    this.envMap = source.envMap;
    this.envMapIntensity = source.envMapIntensity;

    this.refractionRatio = source.refractionRatio;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;
    this.wireframeLinecap = source.wireframeLinecap;
    this.wireframeLinejoin = source.wireframeLinejoin;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;
    this.morphNormals = source.morphNormals;

    return this;

};

/**
 * @author WestLangley / http://github.com/WestLangley
 *
 * parameters = {
 *  reflectivity: <float>
 * }
 */

function MeshPhysicalMaterial( parameters ) {

    MeshStandardMaterial.call( this );

    this.defines = { 'PHYSICAL': '' };

    this.type = 'MeshPhysicalMaterial';

    this.reflectivity = 0.5; // maps to F0 = 0.04

    this.clearCoat = 0.0;
    this.clearCoatRoughness = 0.0;

    this.setValues( parameters );

}

MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;

MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;

MeshPhysicalMaterial.prototype.copy = function ( source ) {

    MeshStandardMaterial.prototype.copy.call( this, source );

    this.defines = { 'PHYSICAL': '' };

    this.reflectivity = source.reflectivity;

    this.clearCoat = source.clearCoat;
    this.clearCoatRoughness = source.clearCoatRoughness;

    return this;

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  specular: <hex>,
 *  shininess: <float>,
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *  lightMapIntensity: <float>
 *
 *  aoMap: new THREE.Texture( <Image> ),
 *  aoMapIntensity: <float>
 *
 *  emissive: <hex>,
 *  emissiveIntensity: <float>
 *  emissiveMap: new THREE.Texture( <Image> ),
 *
 *  bumpMap: new THREE.Texture( <Image> ),
 *  bumpScale: <float>,
 *
 *  normalMap: new THREE.Texture( <Image> ),
 *  normalScale: <Vector2>,
 *
 *  displacementMap: new THREE.Texture( <Image> ),
 *  displacementScale: <float>,
 *  displacementBias: <float>,
 *
 *  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>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>
 * }
 */

function MeshPhongMaterial( parameters ) {

    Material.call( this );

    this.type = 'MeshPhongMaterial';

    this.color = new Color( 0xffffff ); // diffuse
    this.specular = new Color( 0x111111 );
    this.shininess = 30;

    this.map = null;

    this.lightMap = null;
    this.lightMapIntensity = 1.0;

    this.aoMap = null;
    this.aoMapIntensity = 1.0;

    this.emissive = new Color( 0x000000 );
    this.emissiveIntensity = 1.0;
    this.emissiveMap = null;

    this.bumpMap = null;
    this.bumpScale = 1;

    this.normalMap = null;
    this.normalScale = new Vector2( 1, 1 );

    this.displacementMap = null;
    this.displacementScale = 1;
    this.displacementBias = 0;

    this.specularMap = null;

    this.alphaMap = null;

    this.envMap = null;
    this.combine = MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

}

MeshPhongMaterial.prototype = Object.create( Material.prototype );
MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;

MeshPhongMaterial.prototype.isMeshPhongMaterial = true;

MeshPhongMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );
    this.specular.copy( source.specular );
    this.shininess = source.shininess;

    this.map = source.map;

    this.lightMap = source.lightMap;
    this.lightMapIntensity = source.lightMapIntensity;

    this.aoMap = source.aoMap;
    this.aoMapIntensity = source.aoMapIntensity;

    this.emissive.copy( source.emissive );
    this.emissiveMap = source.emissiveMap;
    this.emissiveIntensity = source.emissiveIntensity;

    this.bumpMap = source.bumpMap;
    this.bumpScale = source.bumpScale;

    this.normalMap = source.normalMap;
    this.normalScale.copy( source.normalScale );

    this.displacementMap = source.displacementMap;
    this.displacementScale = source.displacementScale;
    this.displacementBias = source.displacementBias;

    this.specularMap = source.specularMap;

    this.alphaMap = source.alphaMap;

    this.envMap = source.envMap;
    this.combine = source.combine;
    this.reflectivity = source.reflectivity;
    this.refractionRatio = source.refractionRatio;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;
    this.wireframeLinecap = source.wireframeLinecap;
    this.wireframeLinejoin = source.wireframeLinejoin;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;
    this.morphNormals = source.morphNormals;

    return this;

};

/**
 * @author takahirox / http://github.com/takahirox
 *
 * parameters = {
 *  gradientMap: new THREE.Texture( <Image> )
 * }
 */

function MeshToonMaterial( parameters ) {

    MeshPhongMaterial.call( this );

    this.defines = { 'TOON': '' };

    this.type = 'MeshToonMaterial';

    this.gradientMap = null;

    this.setValues( parameters );

}

MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );
MeshToonMaterial.prototype.constructor = MeshToonMaterial;

MeshToonMaterial.prototype.isMeshToonMaterial = true;

MeshToonMaterial.prototype.copy = function ( source ) {

    MeshPhongMaterial.prototype.copy.call( this, source );

    this.gradientMap = source.gradientMap;

    return this;

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
 *
 * parameters = {
 *  opacity: <float>,
 *
 *  bumpMap: new THREE.Texture( <Image> ),
 *  bumpScale: <float>,
 *
 *  normalMap: new THREE.Texture( <Image> ),
 *  normalScale: <Vector2>,
 *
 *  displacementMap: new THREE.Texture( <Image> ),
 *  displacementScale: <float>,
 *  displacementBias: <float>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>
 * }
 */

function MeshNormalMaterial( parameters ) {

    Material.call( this );

    this.type = 'MeshNormalMaterial';

    this.bumpMap = null;
    this.bumpScale = 1;

    this.normalMap = null;
    this.normalScale = new Vector2( 1, 1 );

    this.displacementMap = null;
    this.displacementScale = 1;
    this.displacementBias = 0;

    this.wireframe = false;
    this.wireframeLinewidth = 1;

    this.fog = false;
    this.lights = false;

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

}

MeshNormalMaterial.prototype = Object.create( Material.prototype );
MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;

MeshNormalMaterial.prototype.isMeshNormalMaterial = true;

MeshNormalMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.bumpMap = source.bumpMap;
    this.bumpScale = source.bumpScale;

    this.normalMap = source.normalMap;
    this.normalScale.copy( source.normalScale );

    this.displacementMap = source.displacementMap;
    this.displacementScale = source.displacementScale;
    this.displacementBias = source.displacementBias;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;
    this.morphNormals = source.morphNormals;

    return this;

};

/**
 * @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> ),
 *  lightMapIntensity: <float>
 *
 *  aoMap: new THREE.Texture( <Image> ),
 *  aoMapIntensity: <float>
 *
 *  emissive: <hex>,
 *  emissiveIntensity: <float>
 *  emissiveMap: 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>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>
 * }
 */

function MeshLambertMaterial( parameters ) {

    Material.call( this );

    this.type = 'MeshLambertMaterial';

    this.color = new Color( 0xffffff ); // diffuse

    this.map = null;

    this.lightMap = null;
    this.lightMapIntensity = 1.0;

    this.aoMap = null;
    this.aoMapIntensity = 1.0;

    this.emissive = new Color( 0x000000 );
    this.emissiveIntensity = 1.0;
    this.emissiveMap = null;

    this.specularMap = null;

    this.alphaMap = null;

    this.envMap = null;
    this.combine = MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

}

MeshLambertMaterial.prototype = Object.create( Material.prototype );
MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;

MeshLambertMaterial.prototype.isMeshLambertMaterial = true;

MeshLambertMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );

    this.map = source.map;

    this.lightMap = source.lightMap;
    this.lightMapIntensity = source.lightMapIntensity;

    this.aoMap = source.aoMap;
    this.aoMapIntensity = source.aoMapIntensity;

    this.emissive.copy( source.emissive );
    this.emissiveMap = source.emissiveMap;
    this.emissiveIntensity = source.emissiveIntensity;

    this.specularMap = source.specularMap;

    this.alphaMap = source.alphaMap;

    this.envMap = source.envMap;
    this.combine = source.combine;
    this.reflectivity = source.reflectivity;
    this.refractionRatio = source.refractionRatio;

    this.wireframe = source.wireframe;
    this.wireframeLinewidth = source.wireframeLinewidth;
    this.wireframeLinecap = source.wireframeLinecap;
    this.wireframeLinejoin = source.wireframeLinejoin;

    this.skinning = source.skinning;
    this.morphTargets = source.morphTargets;
    this.morphNormals = source.morphNormals;

    return this;

};

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *
 *  linewidth: <float>,
 *
 *  scale: <float>,
 *  dashSize: <float>,
 *  gapSize: <float>
 * }
 */

function LineDashedMaterial( parameters ) {

    Material.call( this );

    this.type = 'LineDashedMaterial';

    this.color = new Color( 0xffffff );

    this.linewidth = 1;

    this.scale = 1;
    this.dashSize = 3;
    this.gapSize = 1;

    this.lights = false;

    this.setValues( parameters );

}

LineDashedMaterial.prototype = Object.create( Material.prototype );
LineDashedMaterial.prototype.constructor = LineDashedMaterial;

LineDashedMaterial.prototype.isLineDashedMaterial = true;

LineDashedMaterial.prototype.copy = function ( source ) {

    Material.prototype.copy.call( this, source );

    this.color.copy( source.color );

    this.linewidth = source.linewidth;

    this.scale = source.scale;
    this.dashSize = source.dashSize;
    this.gapSize = source.gapSize;

    return this;

};



var Materials = Object.freeze({
    ShadowMaterial: ShadowMaterial,
    SpriteMaterial: SpriteMaterial,
    RawShaderMaterial: RawShaderMaterial,
    ShaderMaterial: ShaderMaterial,
    PointsMaterial: PointsMaterial,
    MeshPhysicalMaterial: MeshPhysicalMaterial,
    MeshStandardMaterial: MeshStandardMaterial,
    MeshPhongMaterial: MeshPhongMaterial,
    MeshToonMaterial: MeshToonMaterial,
    MeshNormalMaterial: MeshNormalMaterial,
    MeshLambertMaterial: MeshLambertMaterial,
    MeshDepthMaterial: MeshDepthMaterial,
    MeshBasicMaterial: MeshBasicMaterial,
    LineDashedMaterial: LineDashedMaterial,
    LineBasicMaterial: LineBasicMaterial,
    Material: Material
});

/**
 * @author mrdoob / http://mrdoob.com/
 */

var Cache = {

    enabled: false,

    files: {},

    add: function ( key, file ) {

        if ( this.enabled === false ) return;

        // console.log( 'THREE.Cache', 'Adding key:', key );

        this.files[ key ] = file;

    },

    get: function ( key ) {

        if ( this.enabled === false ) return;

        // console.log( 'THREE.Cache', 'Checking key:', key );

        return this.files[ key ];

    },

    remove: function ( key ) {

        delete this.files[ key ];

    },

    clear: function () {

        this.files = {};

    }

};

/**
 * @author mrdoob / http://mrdoob.com/
 */

function LoadingManager( onLoad, onProgress, onError ) {

    var scope = this;

    var isLoading = false, itemsLoaded = 0, itemsTotal = 0;

    this.onStart = undefined;
    this.onLoad = onLoad;
    this.onProgress = onProgress;
    this.onError = onError;

    this.itemStart = function ( url ) {

        itemsTotal ++;

        if ( isLoading === false ) {

            if ( scope.onStart !== undefined ) {

                scope.onStart( url, itemsLoaded, itemsTotal );

            }

        }

        isLoading = true;

    };

    this.itemEnd = function ( url ) {

        itemsLoaded ++;

        if ( scope.onProgress !== undefined ) {

            scope.onProgress( url, itemsLoaded, itemsTotal );

        }

        if ( itemsLoaded === itemsTotal ) {

            isLoading = false;

            if ( scope.onLoad !== undefined ) {

                scope.onLoad();

            }

        }

    };

    this.itemError = function ( url ) {

        if ( scope.onError !== undefined ) {

            scope.onError( url );

        }

    };

}

var DefaultLoadingManager = new LoadingManager();

/**
 * @author mrdoob / http://mrdoob.com/
 */

function FileLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( FileLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        if ( url === undefined ) url = '';

        if ( this.path !== undefined ) url = this.path + url;

        var scope = this;

        var cached = Cache.get( url );

        if ( cached !== undefined ) {

            scope.manager.itemStart( url );

            setTimeout( function () {

                if ( onLoad ) onLoad( cached );

                scope.manager.itemEnd( url );

            }, 0 );

            return cached;

        }

        // Check for data: URI
        var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
        var dataUriRegexResult = url.match( dataUriRegex );

        // Safari can not handle Data URIs through XMLHttpRequest so process manually
        if ( dataUriRegexResult ) {

            var mimeType = dataUriRegexResult[ 1 ];
            var isBase64 = !! dataUriRegexResult[ 2 ];
            var data = dataUriRegexResult[ 3 ];

            data = window.decodeURIComponent( data );

            if ( isBase64 ) data = window.atob( data );

            try {

                var response;
                var responseType = ( this.responseType || '' ).toLowerCase();

                switch ( responseType ) {

                    case 'arraybuffer':
                    case 'blob':

                         response = new ArrayBuffer( data.length );

                        var view = new Uint8Array( response );

                        for ( var i = 0; i < data.length; i ++ ) {

                            view[ i ] = data.charCodeAt( i );

                        }

                        if ( responseType === 'blob' ) {

                            response = new Blob( [ response ], { type: mimeType } );

                        }

                        break;

                    case 'document':

                        var parser = new DOMParser();
                        response = parser.parseFromString( data, mimeType );

                        break;

                    case 'json':

                        response = JSON.parse( data );

                        break;

                    default: // 'text' or other

                        response = data;

                        break;

                }

                // Wait for next browser tick
                window.setTimeout( function () {

                    if ( onLoad ) onLoad( response );

                    scope.manager.itemEnd( url );

                }, 0 );

            } catch ( error ) {

                // Wait for next browser tick
                window.setTimeout( function () {

                    if ( onError ) onError( error );

                    scope.manager.itemEnd( url );
                    scope.manager.itemError( url );

                }, 0 );

            }

        } else {

            var request = new XMLHttpRequest();
            request.open( 'GET', url, true );

            request.addEventListener( 'load', function ( event ) {

                var response = event.target.response;

                Cache.add( url, response );

                if ( this.status === 200 ) {

                    if ( onLoad ) onLoad( response );

                    scope.manager.itemEnd( url );

                } else if ( this.status === 0 ) {

                    // Some browsers return HTTP Status 0 when using non-http protocol
                    // e.g. 'file://' or 'data://'. Handle as success.

                    console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );

                    if ( onLoad ) onLoad( response );

                    scope.manager.itemEnd( url );

                } else {

                    if ( onError ) onError( event );

                    scope.manager.itemEnd( url );
                    scope.manager.itemError( url );

                }

            }, false );

            if ( onProgress !== undefined ) {

                request.addEventListener( 'progress', function ( event ) {

                    onProgress( event );

                }, false );

            }

            request.addEventListener( 'error', function ( event ) {

                if ( onError ) onError( event );

                scope.manager.itemEnd( url );
                scope.manager.itemError( url );

            }, false );

            if ( this.responseType !== undefined ) request.responseType = this.responseType;
            if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;

            if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );

            for ( var header in this.requestHeader ) {

                request.setRequestHeader( header, this.requestHeader[ header ] );

            }

            request.send( null );

        }

        scope.manager.itemStart( url );

        return request;

    },

    setPath: function ( value ) {

        this.path = value;
        return this;

    },

    setResponseType: function ( value ) {

        this.responseType = value;
        return this;

    },

    setWithCredentials: function ( value ) {

        this.withCredentials = value;
        return this;

    },

    setMimeType: function ( value ) {

        this.mimeType = value;
        return this;

    },

    setRequestHeader: function ( value ) {

        this.requestHeader = value;
        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 *
 * Abstract Base class to block based textures loader (dds, pvr, ...)
 */

function CompressedTextureLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

    // override in sub classes
    this._parser = null;

}

Object.assign( CompressedTextureLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var images = [];

        var texture = new CompressedTexture();
        texture.image = images;

        var loader = new FileLoader( this.manager );
        loader.setPath( this.path );
        loader.setResponseType( 'arraybuffer' );

        function loadTexture( 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 = LinearFilter;

                    texture.format = texDatas.format;
                    texture.needsUpdate = true;

                    if ( onLoad ) onLoad( texture );

                }

            }, onProgress, onError );

        }

        if ( Array.isArray( url ) ) {

            var loaded = 0;

            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 = LinearFilter;

                }

                texture.format = texDatas.format;
                texture.needsUpdate = true;

                if ( onLoad ) onLoad( texture );

            }, onProgress, onError );

        }

        return texture;

    },

    setPath: function ( value ) {

        this.path = value;
        return this;

    }

} );

/**
 * @author Nikos M. / https://github.com/foo123/
 *
 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
 */

function DataTextureLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

    // override in sub classes
    this._parser = null;

}

Object.assign( DataTextureLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var texture = new DataTexture();

        var loader = new FileLoader( this.manager );
        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 : ClampToEdgeWrapping;
            texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;

            texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;
            texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : 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 = LinearFilter;

            }

            texture.needsUpdate = true;

            if ( onLoad ) onLoad( texture, texData );

        }, onProgress, onError );


        return texture;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function ImageLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( ImageLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        if ( url === undefined ) url = '';

        if ( this.path !== undefined ) url = this.path + url;

        var scope = this;

        var cached = Cache.get( url );

        if ( cached !== undefined ) {

            scope.manager.itemStart( url );

            setTimeout( function () {

                if ( onLoad ) onLoad( cached );

                scope.manager.itemEnd( url );

            }, 0 );

            return cached;

        }

        var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );

        image.addEventListener( 'load', function () {

            Cache.add( url, this );

            if ( onLoad ) onLoad( this );

            scope.manager.itemEnd( url );

        }, false );

        /*
        image.addEventListener( 'progress', function ( event ) {

            if ( onProgress ) onProgress( event );

        }, false );
        */

        image.addEventListener( 'error', function ( event ) {

            if ( onError ) onError( event );

            scope.manager.itemEnd( url );
            scope.manager.itemError( url );

        }, false );

        if ( url.substr( 0, 5 ) !== 'data:' ) {

            if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;

        }

        scope.manager.itemStart( url );

        image.src = url;

        return image;

    },

    setCrossOrigin: function ( value ) {

        this.crossOrigin = value;
        return this;

    },

    setPath: function ( value ) {

        this.path = value;
        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function CubeTextureLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( CubeTextureLoader.prototype, {

    load: function ( urls, onLoad, onProgress, onError ) {

        var texture = new CubeTexture();

        var loader = new ImageLoader( this.manager );
        loader.setCrossOrigin( this.crossOrigin );
        loader.setPath( this.path );

        var loaded = 0;

        function loadTexture( i ) {

            loader.load( urls[ i ], function ( image ) {

                texture.images[ i ] = image;

                loaded ++;

                if ( loaded === 6 ) {

                    texture.needsUpdate = true;

                    if ( onLoad ) onLoad( texture );

                }

            }, undefined, onError );

        }

        for ( var i = 0; i < urls.length; ++ i ) {

            loadTexture( i );

        }

        return texture;

    },

    setCrossOrigin: function ( value ) {

        this.crossOrigin = value;
        return this;

    },

    setPath: function ( value ) {

        this.path = value;
        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function TextureLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( TextureLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var loader = new ImageLoader( this.manager );
        loader.setCrossOrigin( this.crossOrigin );
        loader.setPath( this.path );

        var texture = new Texture();
        texture.image = loader.load( url, function () {

            // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
            var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;

            texture.format = isJPEG ? RGBFormat : RGBAFormat;
            texture.needsUpdate = true;

            if ( onLoad !== undefined ) {

                onLoad( texture );

            }

        }, onProgress, onError );

        return texture;

    },

    setCrossOrigin: function ( value ) {

        this.crossOrigin = value;
        return this;

    },

    setPath: function ( value ) {

        this.path = value;
        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function Light( color, intensity ) {

    Object3D.call( this );

    this.type = 'Light';

    this.color = new Color( color );
    this.intensity = intensity !== undefined ? intensity : 1;

    this.receiveShadow = undefined;

}

Light.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Light,

    isLight: true,

    copy: function ( source ) {

        Object3D.prototype.copy.call( this, source );

        this.color.copy( source.color );
        this.intensity = source.intensity;

        return this;

    },

    toJSON: function ( meta ) {

        var data = Object3D.prototype.toJSON.call( this, meta );

        data.object.color = this.color.getHex();
        data.object.intensity = this.intensity;

        if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();

        if ( this.distance !== undefined ) data.object.distance = this.distance;
        if ( this.angle !== undefined ) data.object.angle = this.angle;
        if ( this.decay !== undefined ) data.object.decay = this.decay;
        if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;

        if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();

        return data;

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 */

function HemisphereLight( skyColor, groundColor, intensity ) {

    Light.call( this, skyColor, intensity );

    this.type = 'HemisphereLight';

    this.castShadow = undefined;

    this.position.copy( Object3D.DefaultUp );
    this.updateMatrix();

    this.groundColor = new Color( groundColor );

}

HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: HemisphereLight,

    isHemisphereLight: true,

    copy: function ( source ) {

        Light.prototype.copy.call( this, source );

        this.groundColor.copy( source.groundColor );

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function LightShadow( camera ) {

    this.camera = camera;

    this.bias = 0;
    this.radius = 1;

    this.mapSize = new Vector2( 512, 512 );

    this.map = null;
    this.matrix = new Matrix4();

}

Object.assign( LightShadow.prototype, {

    copy: function ( source ) {

        this.camera = source.camera.clone();

        this.bias = source.bias;
        this.radius = source.radius;

        this.mapSize.copy( source.mapSize );

        return this;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    toJSON: function () {

        var object = {};

        if ( this.bias !== 0 ) object.bias = this.bias;
        if ( this.radius !== 1 ) object.radius = this.radius;
        if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();

        object.camera = this.camera.toJSON( false ).object;
        delete object.camera.matrix;

        return object;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function SpotLightShadow() {

    LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );

}

SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {

    constructor: SpotLightShadow,

    isSpotLightShadow: true,

    update: function ( light ) {

        var camera = this.camera;

        var fov = _Math.RAD2DEG * 2 * light.angle;
        var aspect = this.mapSize.width / this.mapSize.height;
        var far = light.distance || camera.far;

        if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {

            camera.fov = fov;
            camera.aspect = aspect;
            camera.far = far;
            camera.updateProjectionMatrix();

        }

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 */

function SpotLight( color, intensity, distance, angle, penumbra, decay ) {

    Light.call( this, color, intensity );

    this.type = 'SpotLight';

    this.position.copy( Object3D.DefaultUp );
    this.updateMatrix();

    this.target = new Object3D();

    Object.defineProperty( this, 'power', {
        get: function () {
            // intensity = power per solid angle.
            // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
            return this.intensity * Math.PI;
        },
        set: function ( power ) {
            // intensity = power per solid angle.
            // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
            this.intensity = power / Math.PI;
        }
    } );

    this.distance = ( distance !== undefined ) ? distance : 0;
    this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
    this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
    this.decay = ( decay !== undefined ) ? decay : 1;    // for physically correct lights, should be 2.

    this.shadow = new SpotLightShadow();

}

SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: SpotLight,

    isSpotLight: true,

    copy: function ( source ) {

        Light.prototype.copy.call( this, source );

        this.distance = source.distance;
        this.angle = source.angle;
        this.penumbra = source.penumbra;
        this.decay = source.decay;

        this.target = source.target.clone();

        this.shadow = source.shadow.clone();

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */


function PointLight( color, intensity, distance, decay ) {

    Light.call( this, color, intensity );

    this.type = 'PointLight';

    Object.defineProperty( this, 'power', {
        get: function () {
            // intensity = power per solid angle.
            // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
            return this.intensity * 4 * Math.PI;

        },
        set: function ( power ) {
            // intensity = power per solid angle.
            // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
            this.intensity = power / ( 4 * Math.PI );
        }
    } );

    this.distance = ( distance !== undefined ) ? distance : 0;
    this.decay = ( decay !== undefined ) ? decay : 1;    // for physically correct lights, should be 2.

    this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );

}

PointLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: PointLight,

    isPointLight: true,

    copy: function ( source ) {

        Light.prototype.copy.call( this, source );

        this.distance = source.distance;
        this.decay = source.decay;

        this.shadow = source.shadow.clone();

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function DirectionalLightShadow( ) {

    LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );

}

DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {

    constructor: DirectionalLightShadow

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function DirectionalLight( color, intensity ) {

    Light.call( this, color, intensity );

    this.type = 'DirectionalLight';

    this.position.copy( Object3D.DefaultUp );
    this.updateMatrix();

    this.target = new Object3D();

    this.shadow = new DirectionalLightShadow();

}

DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: DirectionalLight,

    isDirectionalLight: true,

    copy: function ( source ) {

        Light.prototype.copy.call( this, source );

        this.target = source.target.clone();

        this.shadow = source.shadow.clone();

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function AmbientLight( color, intensity ) {

    Light.call( this, color, intensity );

    this.type = 'AmbientLight';

    this.castShadow = undefined;

}

AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: AmbientLight,

    isAmbientLight: true

} );

/**
 * @author abelnation / http://github.com/abelnation
 */

function RectAreaLight( color, intensity, width, height ) {

    Light.call( this, color, intensity );

    this.type = 'RectAreaLight';

    this.position.set( 0, 1, 0 );
    this.updateMatrix();

    this.width = ( width !== undefined ) ? width : 10;
    this.height = ( height !== undefined ) ? height : 10;

    // TODO (abelnation): distance/decay

    // TODO (abelnation): update method for RectAreaLight to update transform to lookat target

    // TODO (abelnation): shadows

}

// TODO (abelnation): RectAreaLight update when light shape is changed
RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {

    constructor: RectAreaLight,

    isRectAreaLight: true,

    copy: function ( source ) {

        Light.prototype.copy.call( this, source );

        this.width = source.width;
        this.height = source.height;

        return this;

    },

    toJSON: function ( meta ) {

        var data = Light.prototype.toJSON.call( this, meta );

        data.object.width = this.width;
        data.object.height = this.height;

        return data;

    }

} );

/**
 * @author tschw
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 */

var AnimationUtils = {

    // same as Array.prototype.slice, but also works on typed arrays
    arraySlice: function ( array, from, to ) {

        if ( AnimationUtils.isTypedArray( array ) ) {

            // in ios9 array.subarray(from, undefined) will return empty array
            // but array.subarray(from) or array.subarray(from, len) is correct
            return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );

        }

        return array.slice( from, to );

    },

    // converts an array to a specific type
    convertArray: function ( array, type, forceClone ) {

        if ( ! array || // let 'undefined' and 'null' pass
                ! forceClone && array.constructor === type ) return array;

        if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {

            return new type( array ); // create typed array

        }

        return Array.prototype.slice.call( array ); // create Array

    },

    isTypedArray: function ( object ) {

        return ArrayBuffer.isView( object ) &&
                ! ( object instanceof DataView );

    },

    // returns an array by which times and values can be sorted
    getKeyframeOrder: function ( times ) {

        function compareTime( i, j ) {

            return times[ i ] - times[ j ];

        }

        var n = times.length;
        var result = new Array( n );
        for ( var i = 0; i !== n; ++ i ) result[ i ] = i;

        result.sort( compareTime );

        return result;

    },

    // uses the array previously returned by 'getKeyframeOrder' to sort data
    sortedArray: function ( values, stride, order ) {

        var nValues = values.length;
        var result = new values.constructor( nValues );

        for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {

            var srcOffset = order[ i ] * stride;

            for ( var j = 0; j !== stride; ++ j ) {

                result[ dstOffset ++ ] = values[ srcOffset + j ];

            }

        }

        return result;

    },

    // function for parsing AOS keyframe formats
    flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {

        var i = 1, key = jsonKeys[ 0 ];

        while ( key !== undefined && key[ valuePropertyName ] === undefined ) {

            key = jsonKeys[ i ++ ];

        }

        if ( key === undefined ) return; // no data

        var value = key[ valuePropertyName ];
        if ( value === undefined ) return; // no data

        if ( Array.isArray( value ) ) {

            do {

                value = key[ valuePropertyName ];

                if ( value !== undefined ) {

                    times.push( key.time );
                    values.push.apply( values, value ); // push all elements

                }

                key = jsonKeys[ i ++ ];

            } while ( key !== undefined );

        } else if ( value.toArray !== undefined ) {

            // ...assume THREE.Math-ish

            do {

                value = key[ valuePropertyName ];

                if ( value !== undefined ) {

                    times.push( key.time );
                    value.toArray( values, values.length );

                }

                key = jsonKeys[ i ++ ];

            } while ( key !== undefined );

        } else {

            // otherwise push as-is

            do {

                value = key[ valuePropertyName ];

                if ( value !== undefined ) {

                    times.push( key.time );
                    values.push( value );

                }

                key = jsonKeys[ i ++ ];

            } while ( key !== undefined );

        }

    }

};

/**
 * Abstract base class of interpolants over parametric samples.
 *
 * The parameter domain is one dimensional, typically the time or a path
 * along a curve defined by the data.
 *
 * The sample values can have any dimensionality and derived classes may
 * apply special interpretations to the data.
 *
 * This class provides the interval seek in a Template Method, deferring
 * the actual interpolation to derived classes.
 *
 * Time complexity is O(1) for linear access crossing at most two points
 * and O(log N) for random access, where N is the number of positions.
 *
 * References:
 *
 *         http://www.oodesign.com/template-method-pattern.html
 *
 * @author tschw
 */

function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {

    this.parameterPositions = parameterPositions;
    this._cachedIndex = 0;

    this.resultBuffer = resultBuffer !== undefined ?
            resultBuffer : new sampleValues.constructor( sampleSize );
    this.sampleValues = sampleValues;
    this.valueSize = sampleSize;

}

Object.assign( Interpolant.prototype, {

    evaluate: function( t ) {

        var pp = this.parameterPositions,
            i1 = this._cachedIndex,

            t1 = pp[   i1   ],
            t0 = pp[ i1 - 1 ];

        validate_interval: {

            seek: {

                var right;

                linear_scan: {
                    //- See http://jsperf.com/comparison-to-undefined/3
                    //- slower code:
                    //-
                    //-                 if ( t >= t1 || t1 === undefined ) {
                    forward_scan: if ( ! ( t < t1 ) ) {

                        for ( var giveUpAt = i1 + 2; ;) {

                            if ( t1 === undefined ) {

                                if ( t < t0 ) break forward_scan;

                                // after end

                                i1 = pp.length;
                                this._cachedIndex = i1;
                                return this.afterEnd_( i1 - 1, t, t0 );

                            }

                            if ( i1 === giveUpAt ) break; // this loop

                            t0 = t1;
                            t1 = pp[ ++ i1 ];

                            if ( t < t1 ) {

                                // we have arrived at the sought interval
                                break seek;

                            }

                        }

                        // prepare binary search on the right side of the index
                        right = pp.length;
                        break linear_scan;

                    }

                    //- slower code:
                    //-                    if ( t < t0 || t0 === undefined ) {
                    if ( ! ( t >= t0 ) ) {

                        // looping?

                        var t1global = pp[ 1 ];

                        if ( t < t1global ) {

                            i1 = 2; // + 1, using the scan for the details
                            t0 = t1global;

                        }

                        // linear reverse scan

                        for ( var giveUpAt = i1 - 2; ;) {

                            if ( t0 === undefined ) {

                                // before start

                                this._cachedIndex = 0;
                                return this.beforeStart_( 0, t, t1 );

                            }

                            if ( i1 === giveUpAt ) break; // this loop

                            t1 = t0;
                            t0 = pp[ -- i1 - 1 ];

                            if ( t >= t0 ) {

                                // we have arrived at the sought interval
                                break seek;

                            }

                        }

                        // prepare binary search on the left side of the index
                        right = i1;
                        i1 = 0;
                        break linear_scan;

                    }

                    // the interval is valid

                    break validate_interval;

                } // linear scan

                // binary search

                while ( i1 < right ) {

                    var mid = ( i1 + right ) >>> 1;

                    if ( t < pp[ mid ] ) {

                        right = mid;

                    } else {

                        i1 = mid + 1;

                    }

                }

                t1 = pp[   i1   ];
                t0 = pp[ i1 - 1 ];

                // check boundary cases, again

                if ( t0 === undefined ) {

                    this._cachedIndex = 0;
                    return this.beforeStart_( 0, t, t1 );

                }

                if ( t1 === undefined ) {

                    i1 = pp.length;
                    this._cachedIndex = i1;
                    return this.afterEnd_( i1 - 1, t0, t );

                }

            } // seek

            this._cachedIndex = i1;

            this.intervalChanged_( i1, t0, t1 );

        } // validate_interval

        return this.interpolate_( i1, t0, t, t1 );

    },

    settings: null, // optional, subclass-specific settings structure
    // Note: The indirection allows central control of many interpolants.

    // --- Protected interface

    DefaultSettings_: {},

    getSettings_: function() {

        return this.settings || this.DefaultSettings_;

    },

    copySampleValue_: function( index ) {

        // copies a sample value to the result buffer

        var result = this.resultBuffer,
            values = this.sampleValues,
            stride = this.valueSize,
            offset = index * stride;

        for ( var i = 0; i !== stride; ++ i ) {

            result[ i ] = values[ offset + i ];

        }

        return result;

    },

    // Template methods for derived classes:

    interpolate_: function( i1, t0, t, t1 ) {

        throw new Error( "call to abstract method" );
        // implementations shall return this.resultBuffer

    },

    intervalChanged_: function( i1, t0, t1 ) {

        // empty

    }

} );

//!\ DECLARE ALIAS AFTER assign prototype !
Object.assign( Interpolant.prototype, {

    //( 0, t, t0 ), returns this.resultBuffer
    beforeStart_: Interpolant.prototype.copySampleValue_,

    //( N-1, tN-1, t ), returns this.resultBuffer
    afterEnd_: Interpolant.prototype.copySampleValue_,

} );

/**
 * Fast and simple cubic spline interpolant.
 *
 * It was derived from a Hermitian construction setting the first derivative
 * at each sample position to the linear slope between neighboring positions
 * over their parameter interval.
 *
 * @author tschw
 */

function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {

    Interpolant.call(
            this, parameterPositions, sampleValues, sampleSize, resultBuffer );

    this._weightPrev = -0;
    this._offsetPrev = -0;
    this._weightNext = -0;
    this._offsetNext = -0;

}

CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {

    constructor: CubicInterpolant,

    DefaultSettings_: {

        endingStart:     ZeroCurvatureEnding,
        endingEnd:        ZeroCurvatureEnding

    },

    intervalChanged_: function( i1, t0, t1 ) {

        var pp = this.parameterPositions,
            iPrev = i1 - 2,
            iNext = i1 + 1,

            tPrev = pp[ iPrev ],
            tNext = pp[ iNext ];

        if ( tPrev === undefined ) {

            switch ( this.getSettings_().endingStart ) {

                case ZeroSlopeEnding:

                    // f'(t0) = 0
                    iPrev = i1;
                    tPrev = 2 * t0 - t1;

                    break;

                case WrapAroundEnding:

                    // use the other end of the curve
                    iPrev = pp.length - 2;
                    tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];

                    break;

                default: // ZeroCurvatureEnding

                    // f''(t0) = 0 a.k.a. Natural Spline
                    iPrev = i1;
                    tPrev = t1;

            }

        }

        if ( tNext === undefined ) {

            switch ( this.getSettings_().endingEnd ) {

                case ZeroSlopeEnding:

                    // f'(tN) = 0
                    iNext = i1;
                    tNext = 2 * t1 - t0;

                    break;

                case WrapAroundEnding:

                    // use the other end of the curve
                    iNext = 1;
                    tNext = t1 + pp[ 1 ] - pp[ 0 ];

                    break;

                default: // ZeroCurvatureEnding

                    // f''(tN) = 0, a.k.a. Natural Spline
                    iNext = i1 - 1;
                    tNext = t0;

            }

        }

        var halfDt = ( t1 - t0 ) * 0.5,
            stride = this.valueSize;

        this._weightPrev = halfDt / ( t0 - tPrev );
        this._weightNext = halfDt / ( tNext - t1 );
        this._offsetPrev = iPrev * stride;
        this._offsetNext = iNext * stride;

    },

    interpolate_: function( i1, t0, t, t1 ) {

        var result = this.resultBuffer,
            values = this.sampleValues,
            stride = this.valueSize,

            o1 = i1 * stride,        o0 = o1 - stride,
            oP = this._offsetPrev,     oN = this._offsetNext,
            wP = this._weightPrev,    wN = this._weightNext,

            p = ( t - t0 ) / ( t1 - t0 ),
            pp = p * p,
            ppp = pp * p;

        // evaluate polynomials

        var sP =     - wP   * ppp   +         2 * wP    * pp    -          wP   * p;
        var s0 = ( 1 + wP ) * ppp   + (-1.5 - 2 * wP )  * pp    + ( -0.5 + wP ) * p     + 1;
        var s1 = (-1 - wN ) * ppp   + ( 1.5 +   wN   )  * pp    +    0.5        * p;
        var sN =       wN   * ppp   -           wN      * pp;

        // combine data linearly

        for ( var i = 0; i !== stride; ++ i ) {

            result[ i ] =
                    sP * values[ oP + i ] +
                    s0 * values[ o0 + i ] +
                    s1 * values[ o1 + i ] +
                    sN * values[ oN + i ];

        }

        return result;

    }

} );

/**
 * @author tschw
 */

function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {

    Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );

}

LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {

    constructor: LinearInterpolant,

    interpolate_: function( i1, t0, t, t1 ) {

        var result = this.resultBuffer,
            values = this.sampleValues,
            stride = this.valueSize,

            offset1 = i1 * stride,
            offset0 = offset1 - stride,

            weight1 = ( t - t0 ) / ( t1 - t0 ),
            weight0 = 1 - weight1;

        for ( var i = 0; i !== stride; ++ i ) {

            result[ i ] =
                    values[ offset0 + i ] * weight0 +
                    values[ offset1 + i ] * weight1;

        }

        return result;

    }

} );

/**
 *
 * Interpolant that evaluates to the sample value at the position preceeding
 * the parameter.
 *
 * @author tschw
 */

function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {

    Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );

}

DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {

    constructor: DiscreteInterpolant,

    interpolate_: function( i1, t0, t, t1 ) {

        return this.copySampleValue_( i1 - 1 );

    }

} );

var KeyframeTrackPrototype;

KeyframeTrackPrototype = {

    TimeBufferType: Float32Array,
    ValueBufferType: Float32Array,

    DefaultInterpolation: InterpolateLinear,

    InterpolantFactoryMethodDiscrete: function ( result ) {

        return new DiscreteInterpolant(
                this.times, this.values, this.getValueSize(), result );

    },

    InterpolantFactoryMethodLinear: function ( result ) {

        return new LinearInterpolant(
                this.times, this.values, this.getValueSize(), result );

    },

    InterpolantFactoryMethodSmooth: function ( result ) {

        return new CubicInterpolant(
                this.times, this.values, this.getValueSize(), result );

    },

    setInterpolation: function ( interpolation ) {

        var factoryMethod;

        switch ( interpolation ) {

            case InterpolateDiscrete:

                factoryMethod = this.InterpolantFactoryMethodDiscrete;

                break;

            case InterpolateLinear:

                factoryMethod = this.InterpolantFactoryMethodLinear;

                break;

            case InterpolateSmooth:

                factoryMethod = this.InterpolantFactoryMethodSmooth;

                break;

        }

        if ( factoryMethod === undefined ) {

            var message = "unsupported interpolation for " +
                    this.ValueTypeName + " keyframe track named " + this.name;

            if ( this.createInterpolant === undefined ) {

                // fall back to default, unless the default itself is messed up
                if ( interpolation !== this.DefaultInterpolation ) {

                    this.setInterpolation( this.DefaultInterpolation );

                } else {

                    throw new Error( message ); // fatal, in this case

                }

            }

            console.warn( 'THREE.KeyframeTrackPrototype:', message );
            return;

        }

        this.createInterpolant = factoryMethod;

    },

    getInterpolation: function () {

        switch ( this.createInterpolant ) {

            case this.InterpolantFactoryMethodDiscrete:

                return InterpolateDiscrete;

            case this.InterpolantFactoryMethodLinear:

                return InterpolateLinear;

            case this.InterpolantFactoryMethodSmooth:

                return InterpolateSmooth;

        }

    },

    getValueSize: function () {

        return this.values.length / this.times.length;

    },

    // move all keyframes either forwards or backwards in time
    shift: function ( timeOffset ) {

        if ( timeOffset !== 0.0 ) {

            var times = this.times;

            for ( var i = 0, n = times.length; i !== n; ++ i ) {

                times[ i ] += timeOffset;

            }

        }

        return this;

    },

    // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
    scale: function ( timeScale ) {

        if ( timeScale !== 1.0 ) {

            var times = this.times;

            for ( var i = 0, n = times.length; i !== n; ++ i ) {

                times[ i ] *= timeScale;

            }

        }

        return this;

    },

    // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
    // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
    trim: function ( startTime, endTime ) {

        var times = this.times,
            nKeys = times.length,
            from = 0,
            to = nKeys - 1;

        while ( from !== nKeys && times[ from ] < startTime ) ++ from;
        while ( to !== - 1 && times[ to ] > endTime ) -- to;

        ++ to; // inclusive -> exclusive bound

        if ( from !== 0 || to !== nKeys ) {

            // empty tracks are forbidden, so keep at least one keyframe
            if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;

            var stride = this.getValueSize();
            this.times = AnimationUtils.arraySlice( times, from, to );
            this.values = AnimationUtils.
                    arraySlice( this.values, from * stride, to * stride );

        }

        return this;

    },

    // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
    validate: function () {

        var valid = true;

        var valueSize = this.getValueSize();
        if ( valueSize - Math.floor( valueSize ) !== 0 ) {

            console.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this );
            valid = false;

        }

        var times = this.times,
            values = this.values,

            nKeys = times.length;

        if ( nKeys === 0 ) {

            console.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this );
            valid = false;

        }

        var prevTime = null;

        for ( var i = 0; i !== nKeys; i ++ ) {

            var currTime = times[ i ];

            if ( typeof currTime === 'number' && isNaN( currTime ) ) {

                console.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime );
                valid = false;
                break;

            }

            if ( prevTime !== null && prevTime > currTime ) {

                console.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime );
                valid = false;
                break;

            }

            prevTime = currTime;

        }

        if ( values !== undefined ) {

            if ( AnimationUtils.isTypedArray( values ) ) {

                for ( var i = 0, n = values.length; i !== n; ++ i ) {

                    var value = values[ i ];

                    if ( isNaN( value ) ) {

                        console.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value );
                        valid = false;
                        break;

                    }

                }

            }

        }

        return valid;

    },

    // removes equivalent sequential keys as common in morph target sequences
    // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
    optimize: function () {

        var times = this.times,
            values = this.values,
            stride = this.getValueSize(),

            smoothInterpolation = this.getInterpolation() === InterpolateSmooth,

            writeIndex = 1,
            lastIndex = times.length - 1;

        for ( var i = 1; i < lastIndex; ++ i ) {

            var keep = false;

            var time = times[ i ];
            var timeNext = times[ i + 1 ];

            // remove adjacent keyframes scheduled at the same time

            if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {

                if ( ! smoothInterpolation ) {

                    // remove unnecessary keyframes same as their neighbors

                    var offset = i * stride,
                        offsetP = offset - stride,
                        offsetN = offset + stride;

                    for ( var j = 0; j !== stride; ++ j ) {

                        var value = values[ offset + j ];

                        if ( value !== values[ offsetP + j ] ||
                                value !== values[ offsetN + j ] ) {

                            keep = true;
                            break;

                        }

                    }

                } else keep = true;

            }

            // in-place compaction

            if ( keep ) {

                if ( i !== writeIndex ) {

                    times[ writeIndex ] = times[ i ];

                    var readOffset = i * stride,
                        writeOffset = writeIndex * stride;

                    for ( var j = 0; j !== stride; ++ j )

                        values[ writeOffset + j ] = values[ readOffset + j ];

                }

                ++ writeIndex;

            }

        }

        // flush last keyframe (compaction looks ahead)

        if ( lastIndex > 0 ) {

            times[ writeIndex ] = times[ lastIndex ];

            for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )

                values[ writeOffset + j ] = values[ readOffset + j ];

            ++ writeIndex;

        }

        if ( writeIndex !== times.length ) {

            this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
            this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );

        }

        return this;

    }

};

function KeyframeTrackConstructor( name, times, values, interpolation ) {

    if ( name === undefined ) throw new Error( "track name is undefined" );

    if ( times === undefined || times.length === 0 ) {

        throw new Error( "no keyframes in track named " + name );

    }

    this.name = name;

    this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
    this.values = AnimationUtils.convertArray( values, this.ValueBufferType );

    this.setInterpolation( interpolation || this.DefaultInterpolation );

    this.validate();
    this.optimize();

}

/**
 *
 * A Track of vectored keyframe values.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function VectorKeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.call( this, name, times, values, interpolation );

}

VectorKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: VectorKeyframeTrack,

    ValueTypeName: 'vector'

    // ValueBufferType is inherited

    // DefaultInterpolation is inherited

} );

/**
 * Spherical linear unit quaternion interpolant.
 *
 * @author tschw
 */

function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {

    Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );

}

QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {

    constructor: QuaternionLinearInterpolant,

    interpolate_: function( i1, t0, t, t1 ) {

        var result = this.resultBuffer,
            values = this.sampleValues,
            stride = this.valueSize,

            offset = i1 * stride,

            alpha = ( t - t0 ) / ( t1 - t0 );

        for ( var end = offset + stride; offset !== end; offset += 4 ) {

            Quaternion.slerpFlat( result, 0,
                    values, offset - stride, values, offset, alpha );

        }

        return result;

    }

} );

/**
 *
 * A Track of quaternion keyframe values.
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function QuaternionKeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.call( this, name, times, values, interpolation );

}

QuaternionKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: QuaternionKeyframeTrack,

    ValueTypeName: 'quaternion',

    // ValueBufferType is inherited

    DefaultInterpolation: InterpolateLinear,

    InterpolantFactoryMethodLinear: function( result ) {

        return new QuaternionLinearInterpolant(
                this.times, this.values, this.getValueSize(), result );

    },

    InterpolantFactoryMethodSmooth: undefined // not yet implemented

} );

/**
 *
 * A Track of numeric keyframe values.
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function NumberKeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.call( this, name, times, values, interpolation );

}

NumberKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: NumberKeyframeTrack,

    ValueTypeName: 'number'

    // ValueBufferType is inherited

    // DefaultInterpolation is inherited

} );

/**
 *
 * A Track that interpolates Strings
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function StringKeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.call( this, name, times, values, interpolation );

}

StringKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: StringKeyframeTrack,

    ValueTypeName: 'string',
    ValueBufferType: Array,

    DefaultInterpolation: InterpolateDiscrete,

    InterpolantFactoryMethodLinear: undefined,

    InterpolantFactoryMethodSmooth: undefined

} );

/**
 *
 * A Track of Boolean keyframe values.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function BooleanKeyframeTrack( name, times, values ) {

    KeyframeTrackConstructor.call( this, name, times, values );

}

BooleanKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: BooleanKeyframeTrack,

    ValueTypeName: 'bool',
    ValueBufferType: Array,

    DefaultInterpolation: InterpolateDiscrete,

    InterpolantFactoryMethodLinear: undefined,
    InterpolantFactoryMethodSmooth: undefined

    // Note: Actually this track could have a optimized / compressed
    // representation of a single value and a custom interpolant that
    // computes "firstValue ^ isOdd( index )".

} );

/**
 *
 * A Track of keyframe values that represent color.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function ColorKeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.call( this, name, times, values, interpolation );

}

ColorKeyframeTrack.prototype =
        Object.assign( Object.create( KeyframeTrackPrototype ), {

    constructor: ColorKeyframeTrack,

    ValueTypeName: 'color'

    // ValueBufferType is inherited

    // DefaultInterpolation is inherited


    // Note: Very basic implementation and nothing special yet.
    // However, this is the place for color space parameterization.

} );

/**
 *
 * A timed sequence of keyframes for a specific property.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function KeyframeTrack( name, times, values, interpolation ) {

    KeyframeTrackConstructor.apply( this, arguments );

}

KeyframeTrack.prototype = KeyframeTrackPrototype;
KeyframeTrackPrototype.constructor = KeyframeTrack;

// Static methods:

Object.assign( KeyframeTrack, {

    // Serialization (in static context, because of constructor invocation
    // and automatic invocation of .toJSON):

    parse: function( json ) {

        if( json.type === undefined ) {

            throw new Error( "track type undefined, can not parse" );

        }

        var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );

        if ( json.times === undefined ) {

            var times = [], values = [];

            AnimationUtils.flattenJSON( json.keys, times, values, 'value' );

            json.times = times;
            json.values = values;

        }

        // derived classes can define a static parse method
        if ( trackType.parse !== undefined ) {

            return trackType.parse( json );

        } else {

            // by default, we asssume a constructor compatible with the base
            return new trackType(
                    json.name, json.times, json.values, json.interpolation );

        }

    },

    toJSON: function( track ) {

        var trackType = track.constructor;

        var json;

        // derived classes can define a static toJSON method
        if ( trackType.toJSON !== undefined ) {

            json = trackType.toJSON( track );

        } else {

            // by default, we assume the data can be serialized as-is
            json = {

                'name': track.name,
                'times': AnimationUtils.convertArray( track.times, Array ),
                'values': AnimationUtils.convertArray( track.values, Array )

            };

            var interpolation = track.getInterpolation();

            if ( interpolation !== track.DefaultInterpolation ) {

                json.interpolation = interpolation;

            }

        }

        json.type = track.ValueTypeName; // mandatory

        return json;

    },

    _getTrackTypeForValueTypeName: function( typeName ) {

        switch( typeName.toLowerCase() ) {

            case "scalar":
            case "double":
            case "float":
            case "number":
            case "integer":

                return NumberKeyframeTrack;

            case "vector":
            case "vector2":
            case "vector3":
            case "vector4":

                return VectorKeyframeTrack;

            case "color":

                return ColorKeyframeTrack;

            case "quaternion":

                return QuaternionKeyframeTrack;

            case "bool":
            case "boolean":

                return BooleanKeyframeTrack;

            case "string":

                return StringKeyframeTrack;

        }

        throw new Error( "Unsupported typeName: " + typeName );

    }

} );

/**
 *
 * Reusable set of Tracks that represent an animation.
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 */

function AnimationClip( name, duration, tracks ) {

    this.name = name;
    this.tracks = tracks;
    this.duration = ( duration !== undefined ) ? duration : - 1;

    this.uuid = _Math.generateUUID();

    // this means it should figure out its duration by scanning the tracks
    if ( this.duration < 0 ) {

        this.resetDuration();

    }

    this.optimize();

}

Object.assign( AnimationClip, {

    parse: function ( json ) {

        var tracks = [],
            jsonTracks = json.tracks,
            frameTime = 1.0 / ( json.fps || 1.0 );

        for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {

            tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );

        }

        return new AnimationClip( json.name, json.duration, tracks );

    },

    toJSON: function ( clip ) {

        var tracks = [],
            clipTracks = clip.tracks;

        var json = {

            'name': clip.name,
            'duration': clip.duration,
            'tracks': tracks

        };

        for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {

            tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );

        }

        return json;

    },

    CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {

        var numMorphTargets = morphTargetSequence.length;
        var tracks = [];

        for ( var i = 0; i < numMorphTargets; i ++ ) {

            var times = [];
            var values = [];

            times.push(
                    ( i + numMorphTargets - 1 ) % numMorphTargets,
                    i,
                    ( i + 1 ) % numMorphTargets );

            values.push( 0, 1, 0 );

            var order = AnimationUtils.getKeyframeOrder( times );
            times = AnimationUtils.sortedArray( times, 1, order );
            values = AnimationUtils.sortedArray( values, 1, order );

            // if there is a key at the first frame, duplicate it as the
            // last frame as well for perfect loop.
            if ( ! noLoop && times[ 0 ] === 0 ) {

                times.push( numMorphTargets );
                values.push( values[ 0 ] );

            }

            tracks.push(
                    new NumberKeyframeTrack(
                        '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
                        times, values
                    ).scale( 1.0 / fps ) );

        }

        return new AnimationClip( name, - 1, tracks );

    },

    findByName: function ( objectOrClipArray, name ) {

        var clipArray = objectOrClipArray;

        if ( ! Array.isArray( objectOrClipArray ) ) {

            var o = objectOrClipArray;
            clipArray = o.geometry && o.geometry.animations || o.animations;

        }

        for ( var i = 0; i < clipArray.length; i ++ ) {

            if ( clipArray[ i ].name === name ) {

                return clipArray[ i ];

            }

        }

        return null;

    },

    CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {

        var animationToMorphTargets = {};

        // tested with https://regex101.com/ on trick sequences
        // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
        var pattern = /^([\w-]*?)([\d]+)$/;

        // sort morph target names into animation groups based
        // patterns like Walk_001, Walk_002, Run_001, Run_002
        for ( var i = 0, il = morphTargets.length; i < il; i ++ ) {

            var morphTarget = morphTargets[ i ];
            var parts = morphTarget.name.match( pattern );

            if ( parts && parts.length > 1 ) {

                var name = parts[ 1 ];

                var animationMorphTargets = animationToMorphTargets[ name ];
                if ( ! animationMorphTargets ) {

                    animationToMorphTargets[ name ] = animationMorphTargets = [];

                }

                animationMorphTargets.push( morphTarget );

            }

        }

        var clips = [];

        for ( var name in animationToMorphTargets ) {

            clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );

        }

        return clips;

    },

    // parse the animation.hierarchy format
    parseAnimation: function ( animation, bones ) {

        if ( ! animation ) {

            console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
            return null;

        }

        var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {

            // only return track if there are actually keys.
            if ( animationKeys.length !== 0 ) {

                var times = [];
                var values = [];

                AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );

                // empty keys are filtered out, so check again
                if ( times.length !== 0 ) {

                    destTracks.push( new trackType( trackName, times, values ) );

                }

            }

        };

        var tracks = [];

        var clipName = animation.name || 'default';
        // automatic length determination in AnimationClip.
        var duration = animation.length || - 1;
        var fps = animation.fps || 30;

        var hierarchyTracks = animation.hierarchy || [];

        for ( var h = 0; h < hierarchyTracks.length; h ++ ) {

            var animationKeys = hierarchyTracks[ h ].keys;

            // skip empty tracks
            if ( ! animationKeys || animationKeys.length === 0 ) continue;

            // process morph targets
            if ( animationKeys[ 0 ].morphTargets ) {

                // figure out all morph targets used in this track
                var morphTargetNames = {};

                for ( var k = 0; k < animationKeys.length; k ++ ) {

                    if ( animationKeys[ k ].morphTargets ) {

                        for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {

                            morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;

                        }

                    }

                }

                // create a track for each morph target with all zero
                // morphTargetInfluences except for the keys in which
                // the morphTarget is named.
                for ( var morphTargetName in morphTargetNames ) {

                    var times = [];
                    var values = [];

                    for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {

                        var animationKey = animationKeys[ k ];

                        times.push( animationKey.time );
                        values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );

                    }

                    tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );

                }

                duration = morphTargetNames.length * ( fps || 1.0 );

            } else {

                // ...assume skeletal animation

                var boneName = '.bones[' + bones[ h ].name + ']';

                addNonemptyTrack(
                        VectorKeyframeTrack, boneName + '.position',
                        animationKeys, 'pos', tracks );

                addNonemptyTrack(
                        QuaternionKeyframeTrack, boneName + '.quaternion',
                        animationKeys, 'rot', tracks );

                addNonemptyTrack(
                        VectorKeyframeTrack, boneName + '.scale',
                        animationKeys, 'scl', tracks );

            }

        }

        if ( tracks.length === 0 ) {

            return null;

        }

        var clip = new AnimationClip( clipName, duration, tracks );

        return clip;

    }

} );

Object.assign( AnimationClip.prototype, {

    resetDuration: function () {

        var tracks = this.tracks, duration = 0;

        for ( var i = 0, n = tracks.length; i !== n; ++ i ) {

            var track = this.tracks[ i ];

            duration = Math.max( duration, track.times[ track.times.length - 1 ] );

        }

        this.duration = duration;

    },

    trim: function () {

        for ( var i = 0; i < this.tracks.length; i ++ ) {

            this.tracks[ i ].trim( 0, this.duration );

        }

        return this;

    },

    optimize: function () {

        for ( var i = 0; i < this.tracks.length; i ++ ) {

            this.tracks[ i ].optimize();

        }

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function MaterialLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
    this.textures = {};

}

Object.assign( MaterialLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var loader = new FileLoader( scope.manager );
        loader.load( url, function ( text ) {

            onLoad( scope.parse( JSON.parse( text ) ) );

        }, onProgress, onError );

    },

    setTextures: function ( value ) {

        this.textures = value;

    },

    parse: function ( json ) {

        var textures = this.textures;

        function getTexture( name ) {

            if ( textures[ name ] === undefined ) {

                console.warn( 'THREE.MaterialLoader: Undefined texture', name );

            }

            return textures[ name ];

        }

        var material = new Materials[ json.type ]();

        if ( json.uuid !== undefined ) material.uuid = json.uuid;
        if ( json.name !== undefined ) material.name = json.name;
        if ( json.color !== undefined ) material.color.setHex( json.color );
        if ( json.roughness !== undefined ) material.roughness = json.roughness;
        if ( json.metalness !== undefined ) material.metalness = json.metalness;
        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.clearCoat !== undefined ) material.clearCoat = json.clearCoat;
        if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;
        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.fog !== undefined ) material.fog = json.fog;
        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.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
        if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
        if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
        if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
        if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
        if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
        if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
        if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
        if ( json.skinning !== undefined ) material.skinning = json.skinning;
        if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;

        // for PointsMaterial

        if ( json.size !== undefined ) material.size = json.size;
        if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;

        // maps

        if ( json.map !== undefined ) material.map = getTexture( json.map );

        if ( json.alphaMap !== undefined ) {

            material.alphaMap = getTexture( json.alphaMap );
            material.transparent = true;

        }

        if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
        if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;

        if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
        if ( json.normalScale !== undefined ) {

            var normalScale = json.normalScale;

            if ( Array.isArray( normalScale ) === false ) {

                // Blender exporter used to export a scalar. See #7459

                normalScale = [ normalScale, normalScale ];

            }

            material.normalScale = new Vector2().fromArray( normalScale );

        }

        if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
        if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
        if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;

        if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
        if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );

        if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
        if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;

        if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );

        if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );

        if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;

        if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
        if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;

        if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
        if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;

        if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );

        return material;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function BufferGeometryLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( BufferGeometryLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var loader = new FileLoader( scope.manager );
        loader.load( url, function ( text ) {

            onLoad( scope.parse( JSON.parse( text ) ) );

        }, onProgress, onError );

    },

    parse: function ( json ) {

        var geometry = new BufferGeometry();

        var index = json.data.index;

        if ( index !== undefined ) {

            var typedArray = new TYPED_ARRAYS[ index.type ]( index.array );
            geometry.setIndex( new BufferAttribute( typedArray, 1 ) );

        }

        var attributes = json.data.attributes;

        for ( var key in attributes ) {

            var attribute = attributes[ key ];
            var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );

            geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );

        }

        var groups = json.data.groups || json.data.drawcalls || json.data.offsets;

        if ( groups !== undefined ) {

            for ( var i = 0, n = groups.length; i !== n; ++ i ) {

                var group = groups[ i ];

                geometry.addGroup( group.start, group.count, group.materialIndex );

            }

        }

        var boundingSphere = json.data.boundingSphere;

        if ( boundingSphere !== undefined ) {

            var center = new Vector3();

            if ( boundingSphere.center !== undefined ) {

                center.fromArray( boundingSphere.center );

            }

            geometry.boundingSphere = new Sphere( center, boundingSphere.radius );

        }

        return geometry;

    }

} );

var TYPED_ARRAYS = {
    Int8Array: Int8Array,
    Uint8Array: Uint8Array,
    // Workaround for IE11 pre KB2929437. See #11440
    Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
    Int16Array: Int16Array,
    Uint16Array: Uint16Array,
    Int32Array: Int32Array,
    Uint32Array: Uint32Array,
    Float32Array: Float32Array,
    Float64Array: Float64Array
};

/**
 * @author alteredq / http://alteredqualia.com/
 */

function Loader() {

    this.onLoadStart = function () {};
    this.onLoadProgress = function () {};
    this.onLoadComplete = function () {};

}

Loader.Handlers = {

    handlers: [],

    add: function ( regex, loader ) {

        this.handlers.push( regex, loader );

    },

    get: function ( file ) {

        var handlers = this.handlers;

        for ( var i = 0, l = handlers.length; i < l; i += 2 ) {

            var regex = handlers[ i ];
            var loader = handlers[ i + 1 ];

            if ( regex.test( file ) ) {

                return loader;

            }

        }

        return null;

    }

};

Object.assign( Loader.prototype, {

    crossOrigin: undefined,

    extractUrlBase: function ( url ) {

        var parts = url.split( '/' );

        if ( parts.length === 1 ) return './';

        parts.pop();

        return parts.join( '/' ) + '/';

    },

    initMaterials: function ( materials, texturePath, crossOrigin ) {

        var array = [];

        for ( var i = 0; i < materials.length; ++ i ) {

            array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );

        }

        return array;

    },

    createMaterial: ( function () {

        var BlendingMode = {
            NoBlending: NoBlending,
            NormalBlending: NormalBlending,
            AdditiveBlending: AdditiveBlending,
            SubtractiveBlending: SubtractiveBlending,
            MultiplyBlending: MultiplyBlending,
            CustomBlending: CustomBlending
        };

        var color = new Color();
        var textureLoader = new TextureLoader();
        var materialLoader = new MaterialLoader();

        return function createMaterial( m, texturePath, crossOrigin ) {

            // convert from old material format

            var textures = {};

            function loadTexture( path, repeat, offset, wrap, anisotropy ) {

                var fullPath = texturePath + path;
                var loader = Loader.Handlers.get( fullPath );

                var texture;

                if ( loader !== null ) {

                    texture = loader.load( fullPath );

                } else {

                    textureLoader.setCrossOrigin( crossOrigin );
                    texture = textureLoader.load( fullPath );

                }

                if ( repeat !== undefined ) {

                    texture.repeat.fromArray( repeat );

                    if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
                    if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;

                }

                if ( offset !== undefined ) {

                    texture.offset.fromArray( offset );

                }

                if ( wrap !== undefined ) {

                    if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
                    if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;

                    if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
                    if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;

                }

                if ( anisotropy !== undefined ) {

                    texture.anisotropy = anisotropy;

                }

                var uuid = _Math.generateUUID();

                textures[ uuid ] = texture;

                return uuid;

            }

            //

            var json = {
                uuid: _Math.generateUUID(),
                type: 'MeshLambertMaterial'
            };

            for ( var name in m ) {

                var value = m[ name ];

                switch ( name ) {

                    case 'DbgColor':
                    case 'DbgIndex':
                    case 'opticalDensity':
                    case 'illumination':
                        break;
                    case 'DbgName':
                        json.name = value;
                        break;
                    case 'blending':
                        json.blending = BlendingMode[ value ];
                        break;
                    case 'colorAmbient':
                    case 'mapAmbient':
                        console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );
                        break;
                    case 'colorDiffuse':
                        json.color = color.fromArray( value ).getHex();
                        break;
                    case 'colorSpecular':
                        json.specular = color.fromArray( value ).getHex();
                        break;
                    case 'colorEmissive':
                        json.emissive = color.fromArray( value ).getHex();
                        break;
                    case 'specularCoef':
                        json.shininess = value;
                        break;
                    case 'shading':
                        if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
                        if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
                        if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
                        break;
                    case 'mapDiffuse':
                        json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
                        break;
                    case 'mapDiffuseRepeat':
                    case 'mapDiffuseOffset':
                    case 'mapDiffuseWrap':
                    case 'mapDiffuseAnisotropy':
                        break;
                    case 'mapEmissive':
                        json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );
                        break;
                    case 'mapEmissiveRepeat':
                    case 'mapEmissiveOffset':
                    case 'mapEmissiveWrap':
                    case 'mapEmissiveAnisotropy':
                        break;
                    case 'mapLight':
                        json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
                        break;
                    case 'mapLightRepeat':
                    case 'mapLightOffset':
                    case 'mapLightWrap':
                    case 'mapLightAnisotropy':
                        break;
                    case 'mapAO':
                        json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );
                        break;
                    case 'mapAORepeat':
                    case 'mapAOOffset':
                    case 'mapAOWrap':
                    case 'mapAOAnisotropy':
                        break;
                    case 'mapBump':
                        json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
                        break;
                    case 'mapBumpScale':
                        json.bumpScale = value;
                        break;
                    case 'mapBumpRepeat':
                    case 'mapBumpOffset':
                    case 'mapBumpWrap':
                    case 'mapBumpAnisotropy':
                        break;
                    case 'mapNormal':
                        json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
                        break;
                    case 'mapNormalFactor':
                        json.normalScale = [ value, value ];
                        break;
                    case 'mapNormalRepeat':
                    case 'mapNormalOffset':
                    case 'mapNormalWrap':
                    case 'mapNormalAnisotropy':
                        break;
                    case 'mapSpecular':
                        json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
                        break;
                    case 'mapSpecularRepeat':
                    case 'mapSpecularOffset':
                    case 'mapSpecularWrap':
                    case 'mapSpecularAnisotropy':
                        break;
                    case 'mapMetalness':
                        json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );
                        break;
                    case 'mapMetalnessRepeat':
                    case 'mapMetalnessOffset':
                    case 'mapMetalnessWrap':
                    case 'mapMetalnessAnisotropy':
                        break;
                    case 'mapRoughness':
                        json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );
                        break;
                    case 'mapRoughnessRepeat':
                    case 'mapRoughnessOffset':
                    case 'mapRoughnessWrap':
                    case 'mapRoughnessAnisotropy':
                        break;
                    case 'mapAlpha':
                        json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
                        break;
                    case 'mapAlphaRepeat':
                    case 'mapAlphaOffset':
                    case 'mapAlphaWrap':
                    case 'mapAlphaAnisotropy':
                        break;
                    case 'flipSided':
                        json.side = BackSide;
                        break;
                    case 'doubleSided':
                        json.side = DoubleSide;
                        break;
                    case 'transparency':
                        console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );
                        json.opacity = value;
                        break;
                    case 'depthTest':
                    case 'depthWrite':
                    case 'colorWrite':
                    case 'opacity':
                    case 'reflectivity':
                    case 'transparent':
                    case 'visible':
                    case 'wireframe':
                        json[ name ] = value;
                        break;
                    case 'vertexColors':
                        if ( value === true ) json.vertexColors = VertexColors;
                        if ( value === 'face' ) json.vertexColors = FaceColors;
                        break;
                    default:
                        console.error( 'THREE.Loader.createMaterial: Unsupported', name, value );
                        break;

                }

            }

            if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
            if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;

            if ( json.opacity < 1 ) json.transparent = true;

            materialLoader.setTextures( textures );

            return materialLoader.parse( json );

        };

    } )()

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

function JSONLoader( manager ) {

    if ( typeof manager === 'boolean' ) {

        console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
        manager = undefined;

    }

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

    this.withCredentials = false;

}

Object.assign( JSONLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );

        var loader = new FileLoader( this.manager );
        loader.setWithCredentials( this.withCredentials );
        loader.load( url, function ( text ) {

            var json = JSON.parse( text );
            var metadata = json.metadata;

            if ( metadata !== undefined ) {

                var type = metadata.type;

                if ( type !== undefined ) {

                    if ( type.toLowerCase() === 'object' ) {

                        console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
                        return;

                    }

                    if ( type.toLowerCase() === 'scene' ) {

                        console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );
                        return;

                    }

                }

            }

            var object = scope.parse( json, texturePath );
            onLoad( object.geometry, object.materials );

        }, onProgress, onError );

    },

    setTexturePath: function ( value ) {

        this.texturePath = value;

    },

    parse: ( function () {

        function parseModel( json, geometry ) {

            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,

                scale = json.scale,

                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 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 Face3();
                    faceA.a = faces[ offset ];
                    faceA.b = faces[ offset + 1 ];
                    faceA.c = faces[ offset + 3 ];

                    faceB = new 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 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 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 Color( hex ) );
                            if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );

                        }

                    }

                    geometry.faces.push( faceA );
                    geometry.faces.push( faceB );

                } else {

                    face = new 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 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 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 Color( colors[ colorIndex ] ) );

                        }

                    }

                    geometry.faces.push( face );

                }

            }

        }

        function parseSkin( json, geometry ) {

            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 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 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 ) ) {

                console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
                    geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );

            }

        }

        function parseMorphing( json, geometry ) {

            var scale = json.scale;

            if ( json.morphTargets !== undefined ) {

                for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {

                    geometry.morphTargets[ i ] = {};
                    geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
                    geometry.morphTargets[ i ].vertices = [];

                    var dstVertices = geometry.morphTargets[ i ].vertices;
                    var srcVertices = json.morphTargets[ i ].vertices;

                    for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {

                        var vertex = new 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 && json.morphColors.length > 0 ) {

                console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );

                var faces = geometry.faces;
                var morphColors = json.morphColors[ 0 ].colors;

                for ( var i = 0, l = faces.length; i < l; i ++ ) {

                    faces[ i ].color.fromArray( morphColors, i * 3 );

                }

            }

        }

        function parseAnimations( json, geometry ) {

            var outputAnimations = [];

            // parse old style Bone/Hierarchy animations
            var animations = [];

            if ( json.animation !== undefined ) {

                animations.push( json.animation );

            }

            if ( json.animations !== undefined ) {

                if ( json.animations.length ) {

                    animations = animations.concat( json.animations );

                } else {

                    animations.push( json.animations );

                }

            }

            for ( var i = 0; i < animations.length; i ++ ) {

                var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
                if ( clip ) outputAnimations.push( clip );

            }

            // parse implicit morph animations
            if ( geometry.morphTargets ) {

                // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
                var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
                outputAnimations = outputAnimations.concat( morphAnimationClips );

            }

            if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;

        }

        return function ( json, texturePath ) {

            if ( json.data !== undefined ) {

                // Geometry 4.0 spec
                json = json.data;

            }

            if ( json.scale !== undefined ) {

                json.scale = 1.0 / json.scale;

            } else {

                json.scale = 1.0;

            }

            var geometry = new Geometry();

            parseModel( json, geometry );
            parseSkin( json, geometry );
            parseMorphing( json, geometry );
            parseAnimations( json, geometry );

            geometry.computeFaceNormals();
            geometry.computeBoundingSphere();

            if ( json.materials === undefined || json.materials.length === 0 ) {

                return { geometry: geometry };

            } else {

                var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );

                return { geometry: geometry, materials: materials };

            }

        };

    } )()

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function ObjectLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
    this.texturePath = '';

}

Object.assign( ObjectLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        if ( this.texturePath === '' ) {

            this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );

        }

        var scope = this;

        var loader = new FileLoader( scope.manager );
        loader.load( url, function ( text ) {

            var json = null;

            try {

                json = JSON.parse( text );

            } catch ( error ) {

                if ( onError !== undefined ) onError( error );

                console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );

                return;

            }

            var metadata = json.metadata;

            if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {

                console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' );
                return;

            }

            scope.parse( json, 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.animations ) {

            object.animations = this.parseAnimations( json.animations );

        }

        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 JSONLoader();
            var bufferGeometryLoader = new 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 Geometries[ data.type ](
                            data.width,
                            data.height,
                            data.widthSegments,
                            data.heightSegments
                        );

                        break;

                    case 'BoxGeometry':
                    case 'BoxBufferGeometry':
                    case 'CubeGeometry': // backwards compatible

                        geometry = new Geometries[ data.type ](
                            data.width,
                            data.height,
                            data.depth,
                            data.widthSegments,
                            data.heightSegments,
                            data.depthSegments
                        );

                        break;

                    case 'CircleGeometry':
                    case 'CircleBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.segments,
                            data.thetaStart,
                            data.thetaLength
                        );

                        break;

                    case 'CylinderGeometry':
                    case 'CylinderBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radiusTop,
                            data.radiusBottom,
                            data.height,
                            data.radialSegments,
                            data.heightSegments,
                            data.openEnded,
                            data.thetaStart,
                            data.thetaLength
                        );

                        break;

                    case 'ConeGeometry':
                    case 'ConeBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.height,
                            data.radialSegments,
                            data.heightSegments,
                            data.openEnded,
                            data.thetaStart,
                            data.thetaLength
                        );

                        break;

                    case 'SphereGeometry':
                    case 'SphereBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.widthSegments,
                            data.heightSegments,
                            data.phiStart,
                            data.phiLength,
                            data.thetaStart,
                            data.thetaLength
                        );

                        break;

                    case 'DodecahedronGeometry':
                    case 'IcosahedronGeometry':
                    case 'OctahedronGeometry':
                    case 'TetrahedronGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.detail
                        );

                        break;

                    case 'RingGeometry':
                    case 'RingBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.innerRadius,
                            data.outerRadius,
                            data.thetaSegments,
                            data.phiSegments,
                            data.thetaStart,
                            data.thetaLength
                        );

                        break;

                    case 'TorusGeometry':
                    case 'TorusBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.tube,
                            data.radialSegments,
                            data.tubularSegments,
                            data.arc
                        );

                        break;

                    case 'TorusKnotGeometry':
                    case 'TorusKnotBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.radius,
                            data.tube,
                            data.tubularSegments,
                            data.radialSegments,
                            data.p,
                            data.q
                        );

                        break;

                    case 'LatheGeometry':
                    case 'LatheBufferGeometry':

                        geometry = new Geometries[ data.type ](
                            data.points,
                            data.segments,
                            data.phiStart,
                            data.phiLength
                        );

                        break;

                    case 'BufferGeometry':

                        geometry = bufferGeometryLoader.parse( data );

                        break;

                    case 'Geometry':

                        geometry = geometryLoader.parse( data, this.texturePath ).geometry;

                        break;

                    default:

                        console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );

                        continue;

                }

                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 loader = new MaterialLoader();
            loader.setTextures( textures );

            for ( var i = 0, l = json.length; i < l; i ++ ) {

                var data = json[ i ];

                if ( data.type === 'MultiMaterial' ) {

                    // Deprecated

                    var array = [];

                    for ( var j = 0; j < data.materials.length; j ++ ) {

                        array.push( loader.parse( data.materials[ j ] ) );

                    }

                    materials[ data.uuid ] = array;

                } else {

                    materials[ data.uuid ] = loader.parse( data );

                }

            }

        }

        return materials;

    },

    parseAnimations: function ( json ) {

        var animations = [];

        for ( var i = 0; i < json.length; i ++ ) {

            var clip = AnimationClip.parse( json[ i ] );

            animations.push( clip );

        }

        return animations;

    },

    parseImages: function ( json, onLoad ) {

        var scope = this;
        var images = {};

        function loadImage( url ) {

            scope.manager.itemStart( url );

            return loader.load( url, function () {

                scope.manager.itemEnd( url );

            }, undefined, function () {

                scope.manager.itemEnd( url );
                scope.manager.itemError( url );

            } );

        }

        if ( json !== undefined && json.length > 0 ) {

            var manager = new LoadingManager( onLoad );

            var loader = new ImageLoader( manager );
            loader.setCrossOrigin( this.crossOrigin );

            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 ) {

        function parseConstant( value, type ) {

            if ( typeof( value ) === 'number' ) return value;

            console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );

            return type[ value ];

        }

        var textures = {};

        if ( json !== undefined ) {

            for ( var i = 0, l = json.length; i < l; i ++ ) {

                var data = json[ i ];

                if ( data.image === undefined ) {

                    console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );

                }

                if ( images[ data.image ] === undefined ) {

                    console.warn( 'THREE.ObjectLoader: Undefined image', data.image );

                }

                var texture = new Texture( images[ data.image ] );
                texture.needsUpdate = true;

                texture.uuid = data.uuid;

                if ( data.name !== undefined ) texture.name = data.name;

                if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );

                if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
                if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
                if ( data.wrap !== undefined ) {

                    texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
                    texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );

                }

                if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
                if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
                if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;

                if ( data.flipY !== undefined ) texture.flipY = data.flipY;

                textures[ data.uuid ] = texture;

            }

        }

        return textures;

    },

    parseObject: function () {

        var matrix = new Matrix4();

        return function parseObject( data, geometries, materials ) {

            var object;

            function getGeometry( name ) {

                if ( geometries[ name ] === undefined ) {

                    console.warn( 'THREE.ObjectLoader: Undefined geometry', name );

                }

                return geometries[ name ];

            }

            function getMaterial( name ) {

                if ( name === undefined ) return undefined;

                if ( Array.isArray( name ) ) {

                    var array = [];

                    for ( var i = 0, l = name.length; i < l; i ++ ) {

                        var uuid = name[ i ];

                        if ( materials[ uuid ] === undefined ) {

                            console.warn( 'THREE.ObjectLoader: Undefined material', uuid );

                        }

                        array.push( materials[ uuid ] );

                    }

                    return array;

                }

                if ( materials[ name ] === undefined ) {

                    console.warn( 'THREE.ObjectLoader: Undefined material', name );

                }

                return materials[ name ];

            }

            switch ( data.type ) {

                case 'Scene':

                    object = new Scene();

                    if ( data.background !== undefined ) {

                        if ( Number.isInteger( data.background ) ) {

                            object.background = new Color( data.background );

                        }

                    }

                    if ( data.fog !== undefined ) {

                        if ( data.fog.type === 'Fog' ) {

                            object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );

                        } else if ( data.fog.type === 'FogExp2' ) {

                            object.fog = new FogExp2( data.fog.color, data.fog.density );

                        }

                    }

                    break;

                case 'PerspectiveCamera':

                    object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );

                    if ( data.focus !== undefined ) object.focus = data.focus;
                    if ( data.zoom !== undefined ) object.zoom = data.zoom;
                    if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
                    if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
                    if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );

                    break;

                case 'OrthographicCamera':

                    object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );

                    break;

                case 'AmbientLight':

                    object = new AmbientLight( data.color, data.intensity );

                    break;

                case 'DirectionalLight':

                    object = new DirectionalLight( data.color, data.intensity );

                    break;

                case 'PointLight':

                    object = new PointLight( data.color, data.intensity, data.distance, data.decay );

                    break;

                case 'RectAreaLight':

                    object = new RectAreaLight( data.color, data.intensity, data.width, data.height );

                    break;

                case 'SpotLight':

                    object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );

                    break;

                case 'HemisphereLight':

                    object = new HemisphereLight( data.color, data.groundColor, data.intensity );

                    break;

                case 'SkinnedMesh':

                    console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' );

                case 'Mesh':

                    var geometry = getGeometry( data.geometry );
                    var material = getMaterial( data.material );

                    if ( geometry.bones && geometry.bones.length > 0 ) {

                        object = new SkinnedMesh( geometry, material );

                    } else {

                        object = new Mesh( geometry, material );

                    }

                    break;

                case 'LOD':

                    object = new LOD();

                    break;

                case 'Line':

                    object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );

                    break;

                case 'LineLoop':

                    object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );

                    break;

                case 'LineSegments':

                    object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );

                    break;

                case 'PointCloud':
                case 'Points':

                    object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );

                    break;

                case 'Sprite':

                    object = new Sprite( getMaterial( data.material ) );

                    break;

                case 'Group':

                    object = new Group();

                    break;

                default:

                    object = new 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.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
                if ( data.scale !== undefined ) object.scale.fromArray( data.scale );

            }

            if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
            if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;

            if ( data.shadow ) {

                if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
                if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
                if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
                if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );

            }

            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 ) );

                }

            }

            if ( data.type === 'LOD' ) {

                var levels = data.levels;

                for ( var l = 0; l < levels.length; l ++ ) {

                    var level = levels[ l ];
                    var child = object.getObjectByProperty( 'uuid', level.object );

                    if ( child !== undefined ) {

                        object.addLevel( child, level.distance );

                    }

                }

            }

            return object;

        };

    }()

} );

var TEXTURE_MAPPING = {
    UVMapping: UVMapping,
    CubeReflectionMapping: CubeReflectionMapping,
    CubeRefractionMapping: CubeRefractionMapping,
    EquirectangularReflectionMapping: EquirectangularReflectionMapping,
    EquirectangularRefractionMapping: EquirectangularRefractionMapping,
    SphericalReflectionMapping: SphericalReflectionMapping,
    CubeUVReflectionMapping: CubeUVReflectionMapping,
    CubeUVRefractionMapping: CubeUVRefractionMapping
};

var TEXTURE_WRAPPING = {
    RepeatWrapping: RepeatWrapping,
    ClampToEdgeWrapping: ClampToEdgeWrapping,
    MirroredRepeatWrapping: MirroredRepeatWrapping
};

var TEXTURE_FILTER = {
    NearestFilter: NearestFilter,
    NearestMipMapNearestFilter: NearestMipMapNearestFilter,
    NearestMipMapLinearFilter: NearestMipMapLinearFilter,
    LinearFilter: LinearFilter,
    LinearMipMapNearestFilter: LinearMipMapNearestFilter,
    LinearMipMapLinearFilter: LinearMipMapLinearFilter
};

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Bezier Curves formulas obtained from
 * http://en.wikipedia.org/wiki/Bézier_curve
 */

function CatmullRom( t, p0, p1, p2, p3 ) {

    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;

}

//

function QuadraticBezierP0( t, p ) {

    var k = 1 - t;
    return k * k * p;

}

function QuadraticBezierP1( t, p ) {

    return 2 * ( 1 - t ) * t * p;

}

function QuadraticBezierP2( t, p ) {

    return t * t * p;

}

function QuadraticBezier( t, p0, p1, p2 ) {

    return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
        QuadraticBezierP2( t, p2 );

}

//

function CubicBezierP0( t, p ) {

    var k = 1 - t;
    return k * k * k * p;

}

function CubicBezierP1( t, p ) {

    var k = 1 - t;
    return 3 * k * k * t * p;

}

function CubicBezierP2( t, p ) {

    return 3 * ( 1 - t ) * t * t * p;

}

function CubicBezierP3( t, p ) {

    return t * t * t * p;

}

function CubicBezier( t, p0, p1, p2, p3 ) {

    return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
        CubicBezierP3( t, p3 );

}

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Extensible curve object
 *
 * Some common of curve methods:
 * .getPoint(t), getTangent(t)
 * .getPointAt(u), getTangentAt(u)
 * .getPoints(), .getSpacedPoints()
 * .getLength()
 * .updateArcLengths()
 *
 * This following curves inherit from THREE.Curve:
 *
 * -- 2D curves --
 * THREE.ArcCurve
 * THREE.CubicBezierCurve
 * THREE.EllipseCurve
 * THREE.LineCurve
 * THREE.QuadraticBezierCurve
 * THREE.SplineCurve
 *
 * -- 3D curves --
 * THREE.CatmullRomCurve3
 * THREE.CubicBezierCurve3
 * THREE.LineCurve3
 * THREE.QuadraticBezierCurve3
 *
 * A series of curves can be represented as a THREE.CurvePath.
 *
 **/

/**************************************************************
 *    Abstract Curve base class
 **************************************************************/

function Curve() {

    this.arcLengthDivisions = 200;

}

Object.assign( Curve.prototype, {

    // Virtual base class method to overwrite and implement in subclasses
    //    - t [0 .. 1]

    getPoint: function () {

        console.warn( 'THREE.Curve: .getPoint() not implemented.' );
        return null;

    },

    // Get point at relative position in curve according to arc length
    // - u [0 .. 1]

    getPointAt: function ( u ) {

        var t = this.getUtoTmapping( u );
        return this.getPoint( t );

    },

    // Get sequence of points using getPoint( t )

    getPoints: function ( divisions ) {

        if ( divisions === undefined ) divisions = 5;

        var points = [];

        for ( var d = 0; d <= divisions; d ++ ) {

            points.push( this.getPoint( d / divisions ) );

        }

        return points;

    },

    // Get sequence of points using getPointAt( u )

    getSpacedPoints: function ( divisions ) {

        if ( divisions === undefined ) divisions = 5;

        var points = [];

        for ( var d = 0; d <= divisions; d ++ ) {

            points.push( this.getPointAt( d / divisions ) );

        }

        return points;

    },

    // Get total curve arc length

    getLength: function () {

        var lengths = this.getLengths();
        return lengths[ lengths.length - 1 ];

    },

    // Get list of cumulative segment lengths

    getLengths: function ( divisions ) {

        if ( divisions === undefined ) divisions = this.arcLengthDivisions;

        if ( this.cacheArcLengths &&
            ( this.cacheArcLengths.length === divisions + 1 ) &&
            ! this.needsUpdate ) {

            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.

    },

    updateArcLengths: function () {

        this.needsUpdate = true;
        this.getLengths();

    },

    // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant

    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 ];

        }

        // 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;

        if ( arcLengths[ i ] === targetArcLength ) {

            return i / ( il - 1 );

        }

        // we could get finer grain at lengths, or use simple interpolation 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

    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();

    },

    getTangentAt: function ( u ) {

        var t = this.getUtoTmapping( u );
        return this.getTangent( t );

    },

    computeFrenetFrames: function ( segments, closed ) {

        // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf

        var normal = new Vector3();

        var tangents = [];
        var normals = [];
        var binormals = [];

        var vec = new Vector3();
        var mat = new Matrix4();

        var i, u, theta;

        // compute the tangent vectors for each segment on the curve

        for ( i = 0; i <= segments; i ++ ) {

            u = i / segments;

            tangents[ i ] = this.getTangentAt( u );
            tangents[ i ].normalize();

        }

        // select an initial normal vector perpendicular to the first tangent vector,
        // and in the direction of the minimum tangent xyz component

        normals[ 0 ] = new Vector3();
        binormals[ 0 ] = new Vector3();
        var min = Number.MAX_VALUE;
        var tx = Math.abs( tangents[ 0 ].x );
        var ty = Math.abs( tangents[ 0 ].y );
        var tz = Math.abs( tangents[ 0 ].z );

        if ( tx <= min ) {

            min = tx;
            normal.set( 1, 0, 0 );

        }

        if ( ty <= min ) {

            min = ty;
            normal.set( 0, 1, 0 );

        }

        if ( tz <= min ) {

            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 curve

        for ( i = 1; i <= segments; i ++ ) {

            normals[ i ] = normals[ i - 1 ].clone();

            binormals[ i ] = binormals[ i - 1 ].clone();

            vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );

            if ( vec.length() > Number.EPSILON ) {

                vec.normalize();

                theta = Math.acos( _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 === true ) {

            theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
            theta /= segments;

            if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {

                theta = - theta;

            }

            for ( i = 1; i <= segments; i ++ ) {

                // twist a little...
                normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
                binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );

            }

        }

        return {
            tangents: tangents,
            normals: normals,
            binormals: binormals
        };

    }

} );

function LineCurve( v1, v2 ) {

    Curve.call( this );

    this.v1 = v1;
    this.v2 = v2;

}

LineCurve.prototype = Object.create( Curve.prototype );
LineCurve.prototype.constructor = LineCurve;

LineCurve.prototype.isLineCurve = true;

LineCurve.prototype.getPoint = function ( t ) {

    if ( t === 1 ) {

        return this.v2.clone();

    }

    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

LineCurve.prototype.getPointAt = function ( u ) {

    return this.getPoint( u );

};

LineCurve.prototype.getTangent = function ( t ) {

    var tangent = this.v2.clone().sub( this.v1 );

    return tangent.normalize();

};

/**
 * @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
 **************************************************************/

function CurvePath() {

    Curve.call( this );

    this.curves = [];

    this.autoClose = false; // Automatically closes the path

}

CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {

    constructor: CurvePath,

    add: function ( curve ) {

        this.curves.push( curve );

    },

    closePath: function () {

        // 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 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')

    getPoint: function ( t ) {

        var d = t * this.getLength();
        var curveLengths = this.getCurveLengths();
        var i = 0;

        // To think about boundaries points.

        while ( i < curveLengths.length ) {

            if ( curveLengths[ i ] >= d ) {

                var diff = curveLengths[ i ] - d;
                var curve = this.curves[ i ];

                var segmentLength = curve.getLength();
                var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;

                return curve.getPointAt( u );

            }

            i ++;

        }

        return null;

        // loop where sum != 0, sum > d , sum+1 <d

    },

    // 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

    getLength: function () {

        var lens = this.getCurveLengths();
        return lens[ lens.length - 1 ];

    },

    // cacheLengths must be recalculated.
    updateArcLengths: function () {

        this.needsUpdate = true;
        this.cacheLengths = null;
        this.getCurveLengths();

    },

    // Compute lengths and cache them
    // We cannot overwrite getLengths() because UtoT mapping uses it.

    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 sub-curve
        // Push sums into cached array

        var lengths = [], sums = 0;

        for ( var i = 0, l = this.curves.length; i < l; i ++ ) {

            sums += this.curves[ i ].getLength();
            lengths.push( sums );

        }

        this.cacheLengths = lengths;

        return lengths;

    },

    getSpacedPoints: function ( divisions ) {

        if ( divisions === undefined ) divisions = 40;

        var points = [];

        for ( var i = 0; i <= divisions; i ++ ) {

            points.push( this.getPoint( i / divisions ) );

        }

        if ( this.autoClose ) {

            points.push( points[ 0 ] );

        }

        return points;

    },

    getPoints: function ( divisions ) {

        divisions = divisions || 12;

        var points = [], last;

        for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {

            var curve = curves[ i ];
            var resolution = (curve && curve.isEllipseCurve) ? divisions * 2
                : (curve && curve.isLineCurve) ? 1
                : (curve && curve.isSplineCurve) ? divisions * curve.points.length
                : divisions;

            var pts = curve.getPoints( resolution );

            for ( var j = 0; j < pts.length; j++ ) {

                var point = pts[ j ];

                if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates

                points.push( point );
                last = point;

            }

        }

        if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {

            points.push( points[ 0 ] );

        }

        return points;

    },

    /**************************************************************
     *    Create Geometries Helpers
     **************************************************************/

    /// Generate geometry from path points (for Line or Points objects)

    createPointsGeometry: function ( divisions ) {

        var pts = this.getPoints( divisions );
        return this.createGeometry( pts );

    },

    // Generate geometry from equidistant sampling along the path

    createSpacedPointsGeometry: function ( divisions ) {

        var pts = this.getSpacedPoints( divisions );
        return this.createGeometry( pts );

    },

    createGeometry: function ( points ) {

        var geometry = new Geometry();

        for ( var i = 0, l = points.length; i < l; i ++ ) {

            var point = points[ i ];
            geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );

        }

        return geometry;

    }

} );

function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {

    Curve.call( this );

    this.aX = aX;
    this.aY = aY;

    this.xRadius = xRadius;
    this.yRadius = yRadius;

    this.aStartAngle = aStartAngle;
    this.aEndAngle = aEndAngle;

    this.aClockwise = aClockwise;

    this.aRotation = aRotation || 0;

}

EllipseCurve.prototype = Object.create( Curve.prototype );
EllipseCurve.prototype.constructor = EllipseCurve;

EllipseCurve.prototype.isEllipseCurve = true;

EllipseCurve.prototype.getPoint = function ( t ) {

    var twoPi = Math.PI * 2;
    var deltaAngle = this.aEndAngle - this.aStartAngle;
    var samePoints = Math.abs( deltaAngle ) < Number.EPSILON;

    // ensures that deltaAngle is 0 .. 2 PI
    while ( deltaAngle < 0 ) deltaAngle += twoPi;
    while ( deltaAngle > twoPi ) deltaAngle -= twoPi;

    if ( deltaAngle < Number.EPSILON ) {

        if ( samePoints ) {

            deltaAngle = 0;

        } else {

            deltaAngle = twoPi;

        }

    }

    if ( this.aClockwise === true && ! samePoints ) {

        if ( deltaAngle === twoPi ) {

            deltaAngle = - twoPi;

        } else {

            deltaAngle = deltaAngle - twoPi;

        }

    }

    var angle = this.aStartAngle + t * deltaAngle;
    var x = this.aX + this.xRadius * Math.cos( angle );
    var y = this.aY + this.yRadius * Math.sin( angle );

    if ( this.aRotation !== 0 ) {

        var cos = Math.cos( this.aRotation );
        var sin = Math.sin( this.aRotation );

        var tx = x - this.aX;
        var ty = y - this.aY;

        // Rotate the point about the center of the ellipse.
        x = tx * cos - ty * sin + this.aX;
        y = tx * sin + ty * cos + this.aY;

    }

    return new Vector2( x, y );

};

function SplineCurve( points /* array of Vector2 */ ) {

    Curve.call( this );

    this.points = ( points === undefined ) ? [] : points;

}

SplineCurve.prototype = Object.create( Curve.prototype );
SplineCurve.prototype.constructor = SplineCurve;

SplineCurve.prototype.isSplineCurve = true;

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 ];

    return new Vector2(
        CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ),
        CatmullRom( weight, point0.y, point1.y, point2.y, point3.y )
    );

};

function CubicBezierCurve( v0, v1, v2, v3 ) {

    Curve.call( this );

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;
    this.v3 = v3;

}

CubicBezierCurve.prototype = Object.create( Curve.prototype );
CubicBezierCurve.prototype.constructor = CubicBezierCurve;

CubicBezierCurve.prototype.getPoint = function ( t ) {

    var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;

    return new Vector2(
        CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
        CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
    );

};

function QuadraticBezierCurve( v0, v1, v2 ) {

    Curve.call( this );

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;

}

QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;

QuadraticBezierCurve.prototype.getPoint = function ( t ) {

    var v0 = this.v0, v1 = this.v1, v2 = this.v2;

    return new Vector2(
        QuadraticBezier( t, v0.x, v1.x, v2.x ),
        QuadraticBezier( t, v0.y, v1.y, v2.y )
    );

};

var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {

    fromPoints: function ( vectors ) {

        this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );

        for ( var i = 1, l = vectors.length; i < l; i ++ ) {

            this.lineTo( vectors[ i ].x, vectors[ i ].y );

        }

    },

    moveTo: function ( x, y ) {

        this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?

    },

    lineTo: function ( x, y ) {

        var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
        this.curves.push( curve );

        this.currentPoint.set( x, y );

    },

    quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {

        var curve = new QuadraticBezierCurve(
            this.currentPoint.clone(),
            new Vector2( aCPx, aCPy ),
            new Vector2( aX, aY )
        );

        this.curves.push( curve );

        this.currentPoint.set( aX, aY );

    },

    bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {

        var curve = new CubicBezierCurve(
            this.currentPoint.clone(),
            new Vector2( aCP1x, aCP1y ),
            new Vector2( aCP2x, aCP2y ),
            new Vector2( aX, aY )
        );

        this.curves.push( curve );

        this.currentPoint.set( aX, aY );

    },

    splineThru: function ( pts /*Array of Vector*/ ) {

        var npts = [ this.currentPoint.clone() ].concat( pts );

        var curve = new SplineCurve( npts );
        this.curves.push( curve );

        this.currentPoint.copy( pts[ pts.length - 1 ] );

    },

    arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {

        var x0 = this.currentPoint.x;
        var y0 = this.currentPoint.y;

        this.absarc( aX + x0, aY + y0, aRadius,
            aStartAngle, aEndAngle, aClockwise );

    },

    absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {

        this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );

    },

    ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {

        var x0 = this.currentPoint.x;
        var y0 = this.currentPoint.y;

        this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );

    },

    absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {

        var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );

        if ( this.curves.length > 0 ) {

            // if a previous curve is present, attempt to join
            var firstPoint = curve.getPoint( 0 );

            if ( ! firstPoint.equals( this.currentPoint ) ) {

                this.lineTo( firstPoint.x, firstPoint.y );

            }

        }

        this.curves.push( curve );

        var lastPoint = curve.getPoint( 1 );
        this.currentPoint.copy( lastPoint );

    }

} );

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Creates free form 2d path using series of points, lines or curves.
 **/

function Path( points ) {

    CurvePath.call( this );
    this.currentPoint = new Vector2();

    if ( points ) {

        this.fromPoints( points );

    }

}

Path.prototype = PathPrototype;
PathPrototype.constructor = Path;

/**
 * @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.

function Shape() {

    Path.apply( this, arguments );

    this.holes = [];

}

Shape.prototype = Object.assign( Object.create( PathPrototype ), {

    constructor: Shape,

    getPointsHoles: function ( divisions ) {

        var holesPts = [];

        for ( var i = 0, l = this.holes.length; i < l; i ++ ) {

            holesPts[ i ] = this.holes[ i ].getPoints( divisions );

        }

        return holesPts;

    },

    // Get points of shape and holes (keypoints based on segments parameter)

    extractAllPoints: function ( divisions ) {

        return {

            shape: this.getPoints( divisions ),
            holes: this.getPointsHoles( divisions )

        };

    },

    extractPoints: function ( divisions ) {

        return this.extractAllPoints( divisions );

    }

} );

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
 **/

function ShapePath() {

    this.subPaths = [];
    this.currentPath = null;

}

Object.assign( ShapePath.prototype, {

    moveTo: function ( x, y ) {

        this.currentPath = new Path();
        this.subPaths.push( this.currentPath );
        this.currentPath.moveTo( x, y );

    },

    lineTo: function ( x, y ) {

        this.currentPath.lineTo( x, y );

    },

    quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {

        this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );

    },

    bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {

        this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );

    },

    splineThru: function ( pts ) {

        this.currentPath.splineThru( pts );

    },

    toShapes: function ( isCCW, noHoles ) {

        function toShapesNoHoles( inSubpaths ) {

            var shapes = [];

            for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {

                var tmpPath = inSubpaths[ i ];

                var tmpShape = new Shape();
                tmpShape.curves = tmpPath.curves;

                shapes.push( tmpShape );

            }

            return shapes;

        }

        function isPointInsidePolygon( inPt, inPolygon ) {

            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 ) > Number.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 collinear
                    if ( inPt.y !== edgeLowPt.y )         continue;            // parallel
                    // edge 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 isClockWise = ShapeUtils.isClockWise;

        var subPaths = this.subPaths;
        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 Shape();
            tmpShape.curves = tmpPath.curves;
            shapes.push( tmpShape );
            return shapes;

        }

        var holesFirst = ! 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 ] = [];

        for ( var i = 0, l = subPaths.length; i < l; i ++ ) {

            tmpPath = subPaths[ i ];
            tmpPoints = tmpPath.getPoints();
            solid = isClockWise( tmpPoints );
            solid = isCCW ? ! solid : solid;

            if ( solid ) {

                if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )    mainIdx ++;

                newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
                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 ambiguous = 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 {

                                ambiguous = true;

                            }

                        }

                    }
                    if ( hole_unassigned ) {

                        betterShapeHoles[ sIdx ].push( ho );

                    }

                }

            }
            // console.log("ambiguous: ", ambiguous);
            if ( toChange.length > 0 ) {

                // console.log("to change: ", toChange);
                if ( ! ambiguous )    newShapeHoles = betterShapeHoles;

            }

        }

        var tmpHoles;

        for ( var i = 0, il = newShapes.length; i < il; i ++ ) {

            tmpShape = newShapes[ i ].s;
            shapes.push( tmpShape );
            tmpHoles = newShapeHoles[ i ];

            for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {

                tmpShape.holes.push( tmpHoles[ j ].h );

            }

        }

        //console.log("shape", shapes);

        return shapes;

    }

} );

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * @author mrdoob / http://mrdoob.com/
 */

function Font( data ) {

    this.data = data;

}

Object.assign( Font.prototype, {

    isFont: true,

    generateShapes: function ( text, size, divisions ) {

        function createPaths( text ) {

            var chars = String( text ).split( '' );
            var scale = size / data.resolution;
            var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;

            var offsetX = 0, offsetY = 0;

            var paths = [];

            for ( var i = 0; i < chars.length; i ++ ) {

                var char = chars[ i ];

                if ( char === '\n' ) {

                    offsetX = 0;
                    offsetY -= line_height;

                } else {

                    var ret = createPath( char, scale, offsetX, offsetY );
                    offsetX += ret.offsetX;
                    paths.push( ret.path );

                }

            }

            return paths;

        }

        function createPath( c, scale, offsetX, offsetY ) {

            var glyph = data.glyphs[ c ] || data.glyphs[ '?' ];

            if ( ! glyph ) return;

            var path = new ShapePath();

            var pts = [];
            var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste;

            if ( glyph.o ) {

                var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );

                for ( var i = 0, l = outline.length; i < l; ) {

                    var action = outline[ i ++ ];

                    switch ( action ) {

                        case 'm': // moveTo

                            x = outline[ i ++ ] * scale + offsetX;
                            y = outline[ i ++ ] * scale + offsetY;

                            path.moveTo( x, y );

                            break;

                        case 'l': // lineTo

                            x = outline[ i ++ ] * scale + offsetX;
                            y = outline[ i ++ ] * scale + offsetY;

                            path.lineTo( x, y );

                            break;

                        case 'q': // quadraticCurveTo

                            cpx  = outline[ i ++ ] * scale + offsetX;
                            cpy  = outline[ i ++ ] * scale + offsetY;
                            cpx1 = outline[ i ++ ] * scale + offsetX;
                            cpy1 = outline[ i ++ ] * scale + offsetY;

                            path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );

                            laste = pts[ pts.length - 1 ];

                            if ( laste ) {

                                cpx0 = laste.x;
                                cpy0 = laste.y;

                                for ( var i2 = 1; i2 <= divisions; i2 ++ ) {

                                    var t = i2 / divisions;
                                    QuadraticBezier( t, cpx0, cpx1, cpx );
                                    QuadraticBezier( t, cpy0, cpy1, cpy );

                                }

                            }

                            break;

                        case 'b': // bezierCurveTo

                            cpx  = outline[ i ++ ] * scale + offsetX;
                            cpy  = outline[ i ++ ] * scale + offsetY;
                            cpx1 = outline[ i ++ ] * scale + offsetX;
                            cpy1 = outline[ i ++ ] * scale + offsetY;
                            cpx2 = outline[ i ++ ] * scale + offsetX;
                            cpy2 = outline[ i ++ ] * scale + offsetY;

                            path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );

                            laste = pts[ pts.length - 1 ];

                            if ( laste ) {

                                cpx0 = laste.x;
                                cpy0 = laste.y;

                                for ( var i2 = 1; i2 <= divisions; i2 ++ ) {

                                    var t = i2 / divisions;
                                    CubicBezier( t, cpx0, cpx1, cpx2, cpx );
                                    CubicBezier( t, cpy0, cpy1, cpy2, cpy );

                                }

                            }

                            break;

                    }

                }

            }

            return { offsetX: glyph.ha * scale, path: path };

        }

        //

        if ( size === undefined ) size = 100;
        if ( divisions === undefined ) divisions = 4;

        var data = this.data;

        var paths = createPaths( text );
        var shapes = [];

        for ( var p = 0, pl = paths.length; p < pl; p ++ ) {

            Array.prototype.push.apply( shapes, paths[ p ].toShapes() );

        }

        return shapes;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function FontLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( FontLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var scope = this;

        var loader = new FileLoader( this.manager );
        loader.load( url, function ( text ) {

            var json;

            try {

                json = JSON.parse( text );

            } catch ( e ) {

                console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
                json = JSON.parse( text.substring( 65, text.length - 2 ) );

            }

            var font = scope.parse( json );

            if ( onLoad ) onLoad( font );

        }, onProgress, onError );

    },

    parse: function ( json ) {

        return new Font( json );

    }

} );

var context;

var AudioContext = {

    getContext: function () {

        if ( context === undefined ) {

            context = new ( window.AudioContext || window.webkitAudioContext )();

        }

        return context;

    },

    setContext: function ( value ) {

        context = value;

    }

};

/**
 * @author Reece Aaron Lecrivain / http://reecenotes.com/
 */

function AudioLoader( manager ) {

    this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

}

Object.assign( AudioLoader.prototype, {

    load: function ( url, onLoad, onProgress, onError ) {

        var loader = new FileLoader( this.manager );
        loader.setResponseType( 'arraybuffer' );
        loader.load( url, function ( buffer ) {

            var context = AudioContext.getContext();

            context.decodeAudioData( buffer, function ( audioBuffer ) {

                onLoad( audioBuffer );

            } );

        }, onProgress, onError );

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function StereoCamera() {

    this.type = 'StereoCamera';

    this.aspect = 1;

    this.eyeSep = 0.064;

    this.cameraL = new PerspectiveCamera();
    this.cameraL.layers.enable( 1 );
    this.cameraL.matrixAutoUpdate = false;

    this.cameraR = new PerspectiveCamera();
    this.cameraR.layers.enable( 2 );
    this.cameraR.matrixAutoUpdate = false;

}

Object.assign( StereoCamera.prototype, {

    update: ( function () {

        var instance, focus, fov, aspect, near, far, zoom, eyeSep;

        var eyeRight = new Matrix4();
        var eyeLeft = new Matrix4();

        return function update( camera ) {

            var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||
                                                aspect !== camera.aspect * this.aspect || near !== camera.near ||
                                                far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep;

            if ( needsUpdate ) {

                instance = this;
                focus = camera.focus;
                fov = camera.fov;
                aspect = camera.aspect * this.aspect;
                near = camera.near;
                far = camera.far;
                zoom = camera.zoom;

                // Off-axis stereoscopic effect based on
                // http://paulbourke.net/stereographics/stereorender/

                var projectionMatrix = camera.projectionMatrix.clone();
                eyeSep = this.eyeSep / 2;
                var eyeSepOnProjection = eyeSep * near / focus;
                var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;
                var xmin, xmax;

                // translate xOffset

                eyeLeft.elements[ 12 ] = - eyeSep;
                eyeRight.elements[ 12 ] = eyeSep;

                // for left eye

                xmin = - ymax * aspect + eyeSepOnProjection;
                xmax = ymax * aspect + eyeSepOnProjection;

                projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
                projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );

                this.cameraL.projectionMatrix.copy( projectionMatrix );

                // for right eye

                xmin = - ymax * aspect - eyeSepOnProjection;
                xmax = ymax * aspect - eyeSepOnProjection;

                projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
                projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );

                this.cameraR.projectionMatrix.copy( projectionMatrix );

            }

            this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
            this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );

        };

    } )()

} );

/**
 * Camera for rendering cube maps
 *    - renders scene into axis-aligned cube
 *
 * @author alteredq / http://alteredqualia.com/
 */

function CubeCamera( near, far, cubeResolution ) {

    Object3D.call( this );

    this.type = 'CubeCamera';

    var fov = 90, aspect = 1;

    var cameraPX = new PerspectiveCamera( fov, aspect, near, far );
    cameraPX.up.set( 0, - 1, 0 );
    cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
    this.add( cameraPX );

    var cameraNX = new PerspectiveCamera( fov, aspect, near, far );
    cameraNX.up.set( 0, - 1, 0 );
    cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
    this.add( cameraNX );

    var cameraPY = new PerspectiveCamera( fov, aspect, near, far );
    cameraPY.up.set( 0, 0, 1 );
    cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
    this.add( cameraPY );

    var cameraNY = new PerspectiveCamera( fov, aspect, near, far );
    cameraNY.up.set( 0, 0, - 1 );
    cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
    this.add( cameraNY );

    var cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
    cameraPZ.up.set( 0, - 1, 0 );
    cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
    this.add( cameraPZ );

    var cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
    cameraNZ.up.set( 0, - 1, 0 );
    cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
    this.add( cameraNZ );

    var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };

    this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );
    this.renderTarget.texture.name = "CubeCamera";

    this.updateCubeMap = function ( renderer, scene ) {

        if ( this.parent === null ) this.updateMatrixWorld();

        var renderTarget = this.renderTarget;
        var generateMipmaps = renderTarget.texture.generateMipmaps;

        renderTarget.texture.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.texture.generateMipmaps = generateMipmaps;

        renderTarget.activeCubeFace = 5;
        renderer.render( scene, cameraNZ, renderTarget );

        renderer.setRenderTarget( null );

    };

}

CubeCamera.prototype = Object.create( Object3D.prototype );
CubeCamera.prototype.constructor = CubeCamera;

/**
 * @author mrdoob / http://mrdoob.com/
 */

function AudioListener() {

    Object3D.call( this );

    this.type = 'AudioListener';

    this.context = AudioContext.getContext();

    this.gain = this.context.createGain();
    this.gain.connect( this.context.destination );

    this.filter = null;

}

AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: AudioListener,

    getInput: function () {

        return this.gain;

    },

    removeFilter: function ( ) {

        if ( this.filter !== null ) {

            this.gain.disconnect( this.filter );
            this.filter.disconnect( this.context.destination );
            this.gain.connect( this.context.destination );
            this.filter = null;

        }

    },

    getFilter: function () {

        return this.filter;

    },

    setFilter: function ( value ) {

        if ( this.filter !== null ) {

            this.gain.disconnect( this.filter );
            this.filter.disconnect( this.context.destination );

        } else {

            this.gain.disconnect( this.context.destination );

        }

        this.filter = value;
        this.gain.connect( this.filter );
        this.filter.connect( this.context.destination );

    },

    getMasterVolume: function () {

        return this.gain.gain.value;

    },

    setMasterVolume: function ( value ) {

        this.gain.gain.value = value;

    },

    updateMatrixWorld: ( function () {

        var position = new Vector3();
        var quaternion = new Quaternion();
        var scale = new Vector3();

        var orientation = new Vector3();

        return function updateMatrixWorld( force ) {

            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 );

            if ( listener.positionX ) {

                listener.positionX.setValueAtTime( position.x, this.context.currentTime );
                listener.positionY.setValueAtTime( position.y, this.context.currentTime );
                listener.positionZ.setValueAtTime( position.z, this.context.currentTime );
                listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );
                listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );
                listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );
                listener.upX.setValueAtTime( up.x, this.context.currentTime );
                listener.upY.setValueAtTime( up.y, this.context.currentTime );
                listener.upZ.setValueAtTime( up.z, this.context.currentTime );

            } else {

                listener.setPosition( position.x, position.y, position.z );
                listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );

            }

        };

    } )()

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Reece Aaron Lecrivain / http://reecenotes.com/
 */

function Audio( listener ) {

    Object3D.call( this );

    this.type = 'Audio';

    this.context = listener.context;

    this.gain = this.context.createGain();
    this.gain.connect( listener.getInput() );

    this.autoplay = false;

    this.buffer = null;
    this.loop = false;
    this.startTime = 0;
    this.playbackRate = 1;
    this.isPlaying = false;
    this.hasPlaybackControl = true;
    this.sourceType = 'empty';

    this.filters = [];

}

Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {

    constructor: Audio,

    getOutput: function () {

        return this.gain;

    },

    setNodeSource: function ( audioNode ) {

        this.hasPlaybackControl = false;
        this.sourceType = 'audioNode';
        this.source = audioNode;
        this.connect();

        return this;

    },

    setBuffer: function ( audioBuffer ) {

        this.buffer = audioBuffer;
        this.sourceType = 'buffer';

        if ( this.autoplay ) this.play();

        return this;

    },

    play: function () {

        if ( this.isPlaying === true ) {

            console.warn( 'THREE.Audio: Audio is already playing.' );
            return;

        }

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return;

        }

        var source = this.context.createBufferSource();

        source.buffer = this.buffer;
        source.loop = this.loop;
        source.onended = this.onEnded.bind( this );
        source.playbackRate.setValueAtTime( this.playbackRate, this.startTime );
        source.start( 0, this.startTime );

        this.isPlaying = true;

        this.source = source;

        return this.connect();

    },

    pause: function () {

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return;

        }

        this.source.stop();
        this.startTime = this.context.currentTime;
        this.isPlaying = false;

        return this;

    },

    stop: function () {

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return;

        }

        this.source.stop();
        this.startTime = 0;
        this.isPlaying = false;

        return this;

    },

    connect: function () {

        if ( this.filters.length > 0 ) {

            this.source.connect( this.filters[ 0 ] );

            for ( var i = 1, l = this.filters.length; i < l; i ++ ) {

                this.filters[ i - 1 ].connect( this.filters[ i ] );

            }

            this.filters[ this.filters.length - 1 ].connect( this.getOutput() );

        } else {

            this.source.connect( this.getOutput() );

        }

        return this;

    },

    disconnect: function () {

        if ( this.filters.length > 0 ) {

            this.source.disconnect( this.filters[ 0 ] );

            for ( var i = 1, l = this.filters.length; i < l; i ++ ) {

                this.filters[ i - 1 ].disconnect( this.filters[ i ] );

            }

            this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );

        } else {

            this.source.disconnect( this.getOutput() );

        }

        return this;

    },

    getFilters: function () {

        return this.filters;

    },

    setFilters: function ( value ) {

        if ( ! value ) value = [];

        if ( this.isPlaying === true ) {

            this.disconnect();
            this.filters = value;
            this.connect();

        } else {

            this.filters = value;

        }

        return this;

    },

    getFilter: function () {

        return this.getFilters()[ 0 ];

    },

    setFilter: function ( filter ) {

        return this.setFilters( filter ? [ filter ] : [] );

    },

    setPlaybackRate: function ( value ) {

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return;

        }

        this.playbackRate = value;

        if ( this.isPlaying === true ) {

            this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );

        }

        return this;

    },

    getPlaybackRate: function () {

        return this.playbackRate;

    },

    onEnded: function () {

        this.isPlaying = false;

    },

    getLoop: function () {

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return false;

        }

        return this.loop;

    },

    setLoop: function ( value ) {

        if ( this.hasPlaybackControl === false ) {

            console.warn( 'THREE.Audio: this Audio has no playback control.' );
            return;

        }

        this.loop = value;

        if ( this.isPlaying === true ) {

            this.source.loop = this.loop;

        }

        return this;

    },

    getVolume: function () {

        return this.gain.gain.value;

    },
    
    setVolume: function ( value ) {

        this.gain.gain.value = value;

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function PositionalAudio( listener ) {

    Audio.call( this, listener );

    this.panner = this.context.createPanner();
    this.panner.connect( this.gain );

}

PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {

    constructor: PositionalAudio,

    getOutput: function () {

        return this.panner;

    },

    getRefDistance: function () {

        return this.panner.refDistance;

    },

    setRefDistance: function ( value ) {

        this.panner.refDistance = value;

    },

    getRolloffFactor: function () {

        return this.panner.rolloffFactor;

    },

    setRolloffFactor: function ( value ) {

        this.panner.rolloffFactor = value;

    },

    getDistanceModel: function () {

        return this.panner.distanceModel;

    },

    setDistanceModel: function ( value ) {

        this.panner.distanceModel = value;

    },

    getMaxDistance: function () {

        return this.panner.maxDistance;

    },

    setMaxDistance: function ( value ) {

        this.panner.maxDistance = value;

    },

    updateMatrixWorld: ( function () {

        var position = new Vector3();

        return function updateMatrixWorld( force ) {

            Object3D.prototype.updateMatrixWorld.call( this, force );

            position.setFromMatrixPosition( this.matrixWorld );

            this.panner.setPosition( position.x, position.y, position.z );

        };

    } )()


} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function AudioAnalyser( audio, fftSize ) {

    this.analyser = audio.context.createAnalyser();
    this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;

    this.data = new Uint8Array( this.analyser.frequencyBinCount );

    audio.getOutput().connect( this.analyser );

}

Object.assign( AudioAnalyser.prototype, {

    getFrequencyData: function () {

        this.analyser.getByteFrequencyData( this.data );

        return this.data;

    },

    getAverageFrequency: function () {

        var value = 0, data = this.getFrequencyData();

        for ( var i = 0; i < data.length; i ++ ) {

            value += data[ i ];

        }

        return value / data.length;

    }

} );

/**
 *
 * Buffered scene graph property that allows weighted accumulation.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function PropertyMixer( binding, typeName, valueSize ) {

    this.binding = binding;
    this.valueSize = valueSize;

    var bufferType = Float64Array,
        mixFunction;

    switch ( typeName ) {

        case 'quaternion':
            mixFunction = this._slerp;
            break;

        case 'string':
        case 'bool':
            bufferType = Array;
            mixFunction = this._select;
            break;

        default:
            mixFunction = this._lerp;

    }

    this.buffer = new bufferType( valueSize * 4 );
    // layout: [ incoming | accu0 | accu1 | orig ]
    //
    // interpolators can use .buffer as their .result
    // the data then goes to 'incoming'
    //
    // 'accu0' and 'accu1' are used frame-interleaved for
    // the cumulative result and are compared to detect
    // changes
    //
    // 'orig' stores the original state of the property

    this._mixBufferRegion = mixFunction;

    this.cumulativeWeight = 0;

    this.useCount = 0;
    this.referenceCount = 0;

}

Object.assign( PropertyMixer.prototype, {

    // accumulate data in the 'incoming' region into 'accu<i>'
    accumulate: function ( accuIndex, weight ) {

        // note: happily accumulating nothing when weight = 0, the caller knows
        // the weight and shouldn't have made the call in the first place

        var buffer = this.buffer,
            stride = this.valueSize,
            offset = accuIndex * stride + stride,

            currentWeight = this.cumulativeWeight;

        if ( currentWeight === 0 ) {

            // accuN := incoming * weight

            for ( var i = 0; i !== stride; ++ i ) {

                buffer[ offset + i ] = buffer[ i ];

            }

            currentWeight = weight;

        } else {

            // accuN := accuN + incoming * weight

            currentWeight += weight;
            var mix = weight / currentWeight;
            this._mixBufferRegion( buffer, offset, 0, mix, stride );

        }

        this.cumulativeWeight = currentWeight;

    },

    // apply the state of 'accu<i>' to the binding when accus differ
    apply: function ( accuIndex ) {

        var stride = this.valueSize,
            buffer = this.buffer,
            offset = accuIndex * stride + stride,

            weight = this.cumulativeWeight,

            binding = this.binding;

        this.cumulativeWeight = 0;

        if ( weight < 1 ) {

            // accuN := accuN + original * ( 1 - cumulativeWeight )

            var originalValueOffset = stride * 3;

            this._mixBufferRegion(
                buffer, offset, originalValueOffset, 1 - weight, stride );

        }

        for ( var i = stride, e = stride + stride; i !== e; ++ i ) {

            if ( buffer[ i ] !== buffer[ i + stride ] ) {

                // value has changed -> update scene graph

                binding.setValue( buffer, offset );
                break;

            }

        }

    },

    // remember the state of the bound property and copy it to both accus
    saveOriginalState: function () {

        var binding = this.binding;

        var buffer = this.buffer,
            stride = this.valueSize,

            originalValueOffset = stride * 3;

        binding.getValue( buffer, originalValueOffset );

        // accu[0..1] := orig -- initially detect changes against the original
        for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {

            buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];

        }

        this.cumulativeWeight = 0;

    },

    // apply the state previously taken via 'saveOriginalState' to the binding
    restoreOriginalState: function () {

        var originalValueOffset = this.valueSize * 3;
        this.binding.setValue( this.buffer, originalValueOffset );

    },


    // mix functions

    _select: function ( buffer, dstOffset, srcOffset, t, stride ) {

        if ( t >= 0.5 ) {

            for ( var i = 0; i !== stride; ++ i ) {

                buffer[ dstOffset + i ] = buffer[ srcOffset + i ];

            }

        }

    },

    _slerp: function ( buffer, dstOffset, srcOffset, t ) {

        Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );

    },

    _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {

        var s = 1 - t;

        for ( var i = 0; i !== stride; ++ i ) {

            var j = dstOffset + i;

            buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;

        }

    }

} );

/**
 *
 * A reference to a real property in the scene graph.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function Composite( targetGroup, path, optionalParsedPath ) {

    var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );

    this._targetGroup = targetGroup;
    this._bindings = targetGroup.subscribe_( path, parsedPath );

}

Object.assign( Composite.prototype, {

    getValue: function ( array, offset ) {

        this.bind(); // bind all binding

        var firstValidIndex = this._targetGroup.nCachedObjects_,
            binding = this._bindings[ firstValidIndex ];

        // and only call .getValue on the first
        if ( binding !== undefined ) binding.getValue( array, offset );

    },

    setValue: function ( array, offset ) {

        var bindings = this._bindings;

        for ( var i = this._targetGroup.nCachedObjects_,
                  n = bindings.length; i !== n; ++ i ) {

            bindings[ i ].setValue( array, offset );

        }

    },

    bind: function () {

        var bindings = this._bindings;

        for ( var i = this._targetGroup.nCachedObjects_,
                  n = bindings.length; i !== n; ++ i ) {

            bindings[ i ].bind();

        }

    },

    unbind: function () {

        var bindings = this._bindings;

        for ( var i = this._targetGroup.nCachedObjects_,
                  n = bindings.length; i !== n; ++ i ) {

            bindings[ i ].unbind();

        }

    }

} );


function PropertyBinding( rootNode, path, parsedPath ) {

    this.path = path;
    this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );

    this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;

    this.rootNode = rootNode;

}

Object.assign( PropertyBinding, {

    Composite: Composite,

    create: function ( root, path, parsedPath ) {

        if ( ! ( root && root.isAnimationObjectGroup ) ) {

            return new PropertyBinding( root, path, parsedPath );

        } else {

            return new PropertyBinding.Composite( root, path, parsedPath );

        }

    },

    /**
     * Replaces spaces with underscores and removes unsupported characters from
     * node names, to ensure compatibility with parseTrackName().
     *
     * @param  {string} name Node name to be sanitized.
     * @return {string}
     */
    sanitizeNodeName: function ( name ) {

        return name.replace( /\s/g, '_' ).replace( /[^\w-]/g, '' );

    },

    parseTrackName: function () {

        // Parent directories, delimited by '/' or ':'. Currently unused, but must
        // be matched to parse the rest of the track name.
        var directoryRe = /((?:[\w-]+[\/:])*)/;

        // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
        var nodeRe = /([\w-\.]+)?/;

        // Object on target node, and accessor. Name may contain only word
        // characters. Accessor may contain any character except closing bracket.
        var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/;

        // Property and accessor. May contain only word characters. Accessor may
        // contain any non-bracket characters.
        var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/;

        var trackRe = new RegExp(''
            + '^'
            + directoryRe.source
            + nodeRe.source
            + objectRe.source
            + propertyRe.source
            + '$'
        );

        var supportedObjectNames = [ 'material', 'materials', 'bones' ];

        return function ( trackName ) {

                var matches = trackRe.exec( trackName );

                if ( ! matches ) {

                    throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );

                }

                var results = {
                    // directoryName: matches[ 1 ], // (tschw) currently unused
                    nodeName: matches[ 2 ],
                    objectName: matches[ 3 ],
                    objectIndex: matches[ 4 ],
                    propertyName: matches[ 5 ],     // required
                    propertyIndex: matches[ 6 ]
                };

                var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );

                if ( lastDot !== undefined && lastDot !== -1 ) {

                    var objectName = results.nodeName.substring( lastDot + 1 );

                    // Object names must be checked against a whitelist. Otherwise, there
                    // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
                    // 'bar' could be the objectName, or part of a nodeName (which can
                    // include '.' characters).
                    if ( supportedObjectNames.indexOf( objectName ) !== -1 ) {

                        results.nodeName = results.nodeName.substring( 0, lastDot );
                        results.objectName = objectName;

                    }

                }

                if ( results.propertyName === null || results.propertyName.length === 0 ) {

                    throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );

                }

                return results;

            };

    }(),

    findNode: function ( root, nodeName ) {

        if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {

            return root;

        }

        // search into skeleton bones.
        if ( root.skeleton ) {

            var searchSkeleton = function ( skeleton ) {

                for ( var i = 0; i < skeleton.bones.length; i ++ ) {

                    var bone = skeleton.bones[ i ];

                    if ( bone.name === nodeName ) {

                        return bone;

                    }

                }

                return null;

            };

            var bone = searchSkeleton( root.skeleton );

            if ( bone ) {

                return bone;

            }

        }

        // search into node subtree.
        if ( root.children ) {

            var searchNodeSubtree = function ( children ) {

                for ( var i = 0; i < children.length; i ++ ) {

                    var childNode = children[ i ];

                    if ( childNode.name === nodeName || childNode.uuid === nodeName ) {

                        return childNode;

                    }

                    var result = searchNodeSubtree( childNode.children );

                    if ( result ) return result;

                }

                return null;

            };

            var subTreeNode = searchNodeSubtree( root.children );

            if ( subTreeNode ) {

                return subTreeNode;

            }

        }

        return null;

    }

} );

Object.assign( PropertyBinding.prototype, { // prototype, continued

    // these are used to "bind" a nonexistent property
    _getValue_unavailable: function () {},
    _setValue_unavailable: function () {},

    BindingType: {
        Direct: 0,
        EntireArray: 1,
        ArrayElement: 2,
        HasFromToArray: 3
    },

    Versioning: {
        None: 0,
        NeedsUpdate: 1,
        MatrixWorldNeedsUpdate: 2
    },

    GetterByBindingType: [

        function getValue_direct( buffer, offset ) {

            buffer[ offset ] = this.node[ this.propertyName ];

        },

        function getValue_array( buffer, offset ) {

            var source = this.resolvedProperty;

            for ( var i = 0, n = source.length; i !== n; ++ i ) {

                buffer[ offset ++ ] = source[ i ];

            }

        },

        function getValue_arrayElement( buffer, offset ) {

            buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];

        },

        function getValue_toArray( buffer, offset ) {

            this.resolvedProperty.toArray( buffer, offset );

        }

    ],

    SetterByBindingTypeAndVersioning: [

        [
            // Direct

            function setValue_direct( buffer, offset ) {

                this.node[ this.propertyName ] = buffer[ offset ];

            },

            function setValue_direct_setNeedsUpdate( buffer, offset ) {

                this.node[ this.propertyName ] = buffer[ offset ];
                this.targetObject.needsUpdate = true;

            },

            function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {

                this.node[ this.propertyName ] = buffer[ offset ];
                this.targetObject.matrixWorldNeedsUpdate = true;

            }

        ], [

            // EntireArray

            function setValue_array( buffer, offset ) {

                var dest = this.resolvedProperty;

                for ( var i = 0, n = dest.length; i !== n; ++ i ) {

                    dest[ i ] = buffer[ offset ++ ];

                }

            },

            function setValue_array_setNeedsUpdate( buffer, offset ) {

                var dest = this.resolvedProperty;

                for ( var i = 0, n = dest.length; i !== n; ++ i ) {

                    dest[ i ] = buffer[ offset ++ ];

                }

                this.targetObject.needsUpdate = true;

            },

            function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {

                var dest = this.resolvedProperty;

                for ( var i = 0, n = dest.length; i !== n; ++ i ) {

                    dest[ i ] = buffer[ offset ++ ];

                }

                this.targetObject.matrixWorldNeedsUpdate = true;

            }

        ], [

            // ArrayElement

            function setValue_arrayElement( buffer, offset ) {

                this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];

            },

            function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {

                this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
                this.targetObject.needsUpdate = true;

            },

            function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {

                this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
                this.targetObject.matrixWorldNeedsUpdate = true;

            }

        ], [

            // HasToFromArray

            function setValue_fromArray( buffer, offset ) {

                this.resolvedProperty.fromArray( buffer, offset );

            },

            function setValue_fromArray_setNeedsUpdate( buffer, offset ) {

                this.resolvedProperty.fromArray( buffer, offset );
                this.targetObject.needsUpdate = true;

            },

            function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {

                this.resolvedProperty.fromArray( buffer, offset );
                this.targetObject.matrixWorldNeedsUpdate = true;

            }

        ]

    ],

    getValue: function getValue_unbound( targetArray, offset ) {

        this.bind();
        this.getValue( targetArray, offset );

        // Note: This class uses a State pattern on a per-method basis:
        // 'bind' sets 'this.getValue' / 'setValue' and shadows the
        // prototype version of these methods with one that represents
        // the bound state. When the property is not found, the methods
        // become no-ops.

    },

    setValue: function getValue_unbound( sourceArray, offset ) {

        this.bind();
        this.setValue( sourceArray, offset );

    },

    // create getter / setter pair for a property in the scene graph
    bind: function () {

        var targetObject = this.node,
            parsedPath = this.parsedPath,

            objectName = parsedPath.objectName,
            propertyName = parsedPath.propertyName,
            propertyIndex = parsedPath.propertyIndex;

        if ( ! targetObject ) {

            targetObject = PropertyBinding.findNode(
                    this.rootNode, parsedPath.nodeName ) || this.rootNode;

            this.node = targetObject;

        }

        // set fail state so we can just 'return' on error
        this.getValue = this._getValue_unavailable;
        this.setValue = this._setValue_unavailable;

        // ensure there is a value node
        if ( ! targetObject ) {

            console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
            return;

        }

        if ( objectName ) {

            var objectIndex = parsedPath.objectIndex;

            // special cases were we need to reach deeper into the hierarchy to get the face materials....
            switch ( objectName ) {

                case 'materials':

                    if ( ! targetObject.material ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
                        return;

                    }

                    if ( ! targetObject.material.materials ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
                        return;

                    }

                    targetObject = targetObject.material.materials;

                    break;

                case 'bones':

                    if ( ! targetObject.skeleton ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
                        return;

                    }

                    // potential future optimization: skip this if propertyIndex is already an integer
                    // and convert the integer string to a true integer.

                    targetObject = targetObject.skeleton.bones;

                    // support resolving morphTarget names into indices.
                    for ( var i = 0; i < targetObject.length; i ++ ) {

                        if ( targetObject[ i ].name === objectIndex ) {

                            objectIndex = i;
                            break;

                        }

                    }

                    break;

                default:

                    if ( targetObject[ objectName ] === undefined ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
                        return;

                    }

                    targetObject = targetObject[ objectName ];

            }


            if ( objectIndex !== undefined ) {

                if ( targetObject[ objectIndex ] === undefined ) {

                    console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
                    return;

                }

                targetObject = targetObject[ objectIndex ];

            }

        }

        // resolve property
        var nodeProperty = targetObject[ propertyName ];

        if ( nodeProperty === undefined ) {

            var nodeName = parsedPath.nodeName;

            console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
                '.' + propertyName + ' but it wasn\'t found.', targetObject );
            return;

        }

        // determine versioning scheme
        var versioning = this.Versioning.None;

        if ( targetObject.needsUpdate !== undefined ) { // material

            versioning = this.Versioning.NeedsUpdate;
            this.targetObject = targetObject;

        } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform

            versioning = this.Versioning.MatrixWorldNeedsUpdate;
            this.targetObject = targetObject;

        }

        // determine how the property gets bound
        var bindingType = this.BindingType.Direct;

        if ( propertyIndex !== undefined ) {

            // access a sub element of the property array (only primitives are supported right now)

            if ( propertyName === "morphTargetInfluences" ) {

                // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.

                // support resolving morphTarget names into indices.
                if ( ! targetObject.geometry ) {

                    console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
                    return;

                }

                if ( targetObject.geometry.isBufferGeometry ) {

                    if ( ! targetObject.geometry.morphAttributes ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
                        return;

                    }

                    for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {

                        if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {

                            propertyIndex = i;
                            break;

                        }

                    }


                } else {

                    if ( ! targetObject.geometry.morphTargets ) {

                        console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
                        return;

                    }

                    for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {

                        if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {

                            propertyIndex = i;
                            break;

                        }

                    }

                }

            }

            bindingType = this.BindingType.ArrayElement;

            this.resolvedProperty = nodeProperty;
            this.propertyIndex = propertyIndex;

        } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {

            // must use copy for Object3D.Euler/Quaternion

            bindingType = this.BindingType.HasFromToArray;

            this.resolvedProperty = nodeProperty;

        } else if ( Array.isArray( nodeProperty ) ) {

            bindingType = this.BindingType.EntireArray;

            this.resolvedProperty = nodeProperty;

        } else {

            this.propertyName = propertyName;

        }

        // select getter / setter
        this.getValue = this.GetterByBindingType[ bindingType ];
        this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];

    },

    unbind: function () {

        this.node = null;

        // back to the prototype version of getValue / setValue
        // note: avoiding to mutate the shape of 'this' via 'delete'
        this.getValue = this._getValue_unbound;
        this.setValue = this._setValue_unbound;

    }

} );

//!\ DECLARE ALIAS AFTER assign prototype !
Object.assign( PropertyBinding.prototype, {

    // initial state of these methods that calls 'bind'
    _getValue_unbound: PropertyBinding.prototype.getValue,
    _setValue_unbound: PropertyBinding.prototype.setValue,

} );

/**
 *
 * A group of objects that receives a shared animation state.
 *
 * Usage:
 *
 *     -    Add objects you would otherwise pass as 'root' to the
 *         constructor or the .clipAction method of AnimationMixer.
 *
 *     -    Instead pass this object as 'root'.
 *
 *     -    You can also add and remove objects later when the mixer
 *         is running.
 *
 * Note:
 *
 *      Objects of this class appear as one object to the mixer,
 *      so cache control of the individual objects must be done
 *      on the group.
 *
 * Limitation:
 *
 *     -     The animated properties must be compatible among the
 *         all objects in the group.
 *
 *  -    A single property can either be controlled through a
 *      target group or directly, but not both.
 *
 * @author tschw
 */

function AnimationObjectGroup( var_args ) {

    this.uuid = _Math.generateUUID();

    // cached objects followed by the active ones
    this._objects = Array.prototype.slice.call( arguments );

    this.nCachedObjects_ = 0;            // threshold
    // note: read by PropertyBinding.Composite

    var indices = {};
    this._indicesByUUID = indices;        // for bookkeeping

    for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

        indices[ arguments[ i ].uuid ] = i;

    }

    this._paths = [];                    // inside: string
    this._parsedPaths = [];                // inside: { we don't care, here }
    this._bindings = [];                 // inside: Array< PropertyBinding >
    this._bindingsIndicesByPath = {};     // inside: indices in these arrays

    var scope = this;

    this.stats = {

        objects: {
            get total() { return scope._objects.length; },
            get inUse() { return this.total - scope.nCachedObjects_; }
        },

        get bindingsPerObject() { return scope._bindings.length; }

    };

}

Object.assign( AnimationObjectGroup.prototype, {

    isAnimationObjectGroup: true,

    add: function( var_args ) {

        var objects = this._objects,
            nObjects = objects.length,
            nCachedObjects = this.nCachedObjects_,
            indicesByUUID = this._indicesByUUID,
            paths = this._paths,
            parsedPaths = this._parsedPaths,
            bindings = this._bindings,
            nBindings = bindings.length;

        for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

            var object = arguments[ i ],
                uuid = object.uuid,
                index = indicesByUUID[ uuid ],
                knownObject = undefined;

            if ( index === undefined ) {

                // unknown object -> add it to the ACTIVE region

                index = nObjects ++;
                indicesByUUID[ uuid ] = index;
                objects.push( object );

                // accounting is done, now do the same for all bindings

                for ( var j = 0, m = nBindings; j !== m; ++ j ) {

                    bindings[ j ].push(
                            new PropertyBinding(
                                object, paths[ j ], parsedPaths[ j ] ) );

                }

            } else if ( index < nCachedObjects ) {

                knownObject = objects[ index ];

                // move existing object to the ACTIVE region

                var firstActiveIndex = -- nCachedObjects,
                    lastCachedObject = objects[ firstActiveIndex ];

                indicesByUUID[ lastCachedObject.uuid ] = index;
                objects[ index ] = lastCachedObject;

                indicesByUUID[ uuid ] = firstActiveIndex;
                objects[ firstActiveIndex ] = object;

                // accounting is done, now do the same for all bindings

                for ( var j = 0, m = nBindings; j !== m; ++ j ) {

                    var bindingsForPath = bindings[ j ],
                        lastCached = bindingsForPath[ firstActiveIndex ],
                        binding = bindingsForPath[ index ];

                    bindingsForPath[ index ] = lastCached;

                    if ( binding === undefined ) {

                        // since we do not bother to create new bindings
                        // for objects that are cached, the binding may
                        // or may not exist

                        binding = new PropertyBinding(
                                object, paths[ j ], parsedPaths[ j ] );

                    }

                    bindingsForPath[ firstActiveIndex ] = binding;

                }

            } else if ( objects[ index ] !== knownObject ) {

                console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
                        'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );

            } // else the object is already where we want it to be

        } // for arguments

        this.nCachedObjects_ = nCachedObjects;

    },

    remove: function( var_args ) {

        var objects = this._objects,
            nCachedObjects = this.nCachedObjects_,
            indicesByUUID = this._indicesByUUID,
            bindings = this._bindings,
            nBindings = bindings.length;

        for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

            var object = arguments[ i ],
                uuid = object.uuid,
                index = indicesByUUID[ uuid ];

            if ( index !== undefined && index >= nCachedObjects ) {

                // move existing object into the CACHED region

                var lastCachedIndex = nCachedObjects ++,
                    firstActiveObject = objects[ lastCachedIndex ];

                indicesByUUID[ firstActiveObject.uuid ] = index;
                objects[ index ] = firstActiveObject;

                indicesByUUID[ uuid ] = lastCachedIndex;
                objects[ lastCachedIndex ] = object;

                // accounting is done, now do the same for all bindings

                for ( var j = 0, m = nBindings; j !== m; ++ j ) {

                    var bindingsForPath = bindings[ j ],
                        firstActive = bindingsForPath[ lastCachedIndex ],
                        binding = bindingsForPath[ index ];

                    bindingsForPath[ index ] = firstActive;
                    bindingsForPath[ lastCachedIndex ] = binding;

                }

            }

        } // for arguments

        this.nCachedObjects_ = nCachedObjects;

    },

    // remove & forget
    uncache: function( var_args ) {

        var objects = this._objects,
            nObjects = objects.length,
            nCachedObjects = this.nCachedObjects_,
            indicesByUUID = this._indicesByUUID,
            bindings = this._bindings,
            nBindings = bindings.length;

        for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

            var object = arguments[ i ],
                uuid = object.uuid,
                index = indicesByUUID[ uuid ];

            if ( index !== undefined ) {

                delete indicesByUUID[ uuid ];

                if ( index < nCachedObjects ) {

                    // object is cached, shrink the CACHED region

                    var firstActiveIndex = -- nCachedObjects,
                        lastCachedObject = objects[ firstActiveIndex ],
                        lastIndex = -- nObjects,
                        lastObject = objects[ lastIndex ];

                    // last cached object takes this object's place
                    indicesByUUID[ lastCachedObject.uuid ] = index;
                    objects[ index ] = lastCachedObject;

                    // last object goes to the activated slot and pop
                    indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
                    objects[ firstActiveIndex ] = lastObject;
                    objects.pop();

                    // accounting is done, now do the same for all bindings

                    for ( var j = 0, m = nBindings; j !== m; ++ j ) {

                        var bindingsForPath = bindings[ j ],
                            lastCached = bindingsForPath[ firstActiveIndex ],
                            last = bindingsForPath[ lastIndex ];

                        bindingsForPath[ index ] = lastCached;
                        bindingsForPath[ firstActiveIndex ] = last;
                        bindingsForPath.pop();

                    }

                } else {

                    // object is active, just swap with the last and pop

                    var lastIndex = -- nObjects,
                        lastObject = objects[ lastIndex ];

                    indicesByUUID[ lastObject.uuid ] = index;
                    objects[ index ] = lastObject;
                    objects.pop();

                    // accounting is done, now do the same for all bindings

                    for ( var j = 0, m = nBindings; j !== m; ++ j ) {

                        var bindingsForPath = bindings[ j ];

                        bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
                        bindingsForPath.pop();

                    }

                } // cached or active

            } // if object is known

        } // for arguments

        this.nCachedObjects_ = nCachedObjects;

    },

    // Internal interface used by befriended PropertyBinding.Composite:

    subscribe_: function ( path, parsedPath ) {

        // returns an array of bindings for the given path that is changed
        // according to the contained objects in the group

        var indicesByPath = this._bindingsIndicesByPath,
            index = indicesByPath[ path ],
            bindings = this._bindings;

        if ( index !== undefined ) return bindings[ index ];

        var paths = this._paths,
            parsedPaths = this._parsedPaths,
            objects = this._objects,
            nObjects = objects.length,
            nCachedObjects = this.nCachedObjects_,
            bindingsForPath = new Array( nObjects );

        index = bindings.length;

        indicesByPath[ path ] = index;

        paths.push( path );
        parsedPaths.push( parsedPath );
        bindings.push( bindingsForPath );

        for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {

            var object = objects[ i ];
            bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );

        }

        return bindingsForPath;

    },

    unsubscribe_: function ( path ) {

        // tells the group to forget about a property path and no longer
        // update the array previously obtained with 'subscribe_'

        var indicesByPath = this._bindingsIndicesByPath,
            index = indicesByPath[ path ];

        if ( index !== undefined ) {

            var paths = this._paths,
                parsedPaths = this._parsedPaths,
                bindings = this._bindings,
                lastBindingsIndex = bindings.length - 1,
                lastBindings = bindings[ lastBindingsIndex ],
                lastBindingsPath = path[ lastBindingsIndex ];

            indicesByPath[ lastBindingsPath ] = index;

            bindings[ index ] = lastBindings;
            bindings.pop();

            parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
            parsedPaths.pop();

            paths[ index ] = paths[ lastBindingsIndex ];
            paths.pop();

        }

    }

} );

/**
 *
 * Action provided by AnimationMixer for scheduling clip playback on specific
 * objects.
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 *
 */

function AnimationAction( mixer, clip, localRoot ) {

    this._mixer = mixer;
    this._clip = clip;
    this._localRoot = localRoot || null;

    var tracks = clip.tracks,
        nTracks = tracks.length,
        interpolants = new Array( nTracks );

    var interpolantSettings = {
            endingStart:     ZeroCurvatureEnding,
            endingEnd:        ZeroCurvatureEnding
    };

    for ( var i = 0; i !== nTracks; ++ i ) {

        var interpolant = tracks[ i ].createInterpolant( null );
        interpolants[ i ] = interpolant;
        interpolant.settings = interpolantSettings;

    }

    this._interpolantSettings = interpolantSettings;

    this._interpolants = interpolants;    // bound by the mixer

    // inside: PropertyMixer (managed by the mixer)
    this._propertyBindings = new Array( nTracks );

    this._cacheIndex = null;            // for the memory manager
    this._byClipCacheIndex = null;        // for the memory manager

    this._timeScaleInterpolant = null;
    this._weightInterpolant = null;

    this.loop = LoopRepeat;
    this._loopCount = -1;

    // global mixer time when the action is to be started
    // it's set back to 'null' upon start of the action
    this._startTime = null;

    // scaled local time of the action
    // gets clamped or wrapped to 0..clip.duration according to loop
    this.time = 0;

    this.timeScale = 1;
    this._effectiveTimeScale = 1;

    this.weight = 1;
    this._effectiveWeight = 1;

    this.repetitions = Infinity;         // no. of repetitions when looping

    this.paused = false;                // true -> zero effective time scale
    this.enabled = true;                // false -> zero effective weight

    this.clampWhenFinished     = false;    // keep feeding the last frame?

    this.zeroSlopeAtStart     = true;        // for smooth interpolation w/o separate
    this.zeroSlopeAtEnd        = true;        // clips for start, loop and end

}

Object.assign( AnimationAction.prototype, {

    // State & Scheduling

    play: function() {

        this._mixer._activateAction( this );

        return this;

    },

    stop: function() {

        this._mixer._deactivateAction( this );

        return this.reset();

    },

    reset: function() {

        this.paused = false;
        this.enabled = true;

        this.time = 0;            // restart clip
        this._loopCount = -1;    // forget previous loops
        this._startTime = null;    // forget scheduling

        return this.stopFading().stopWarping();

    },

    isRunning: function() {

        return this.enabled && ! this.paused && this.timeScale !== 0 &&
                this._startTime === null && this._mixer._isActiveAction( this );

    },

    // return true when play has been called
    isScheduled: function() {

        return this._mixer._isActiveAction( this );

    },

    startAt: function( time ) {

        this._startTime = time;

        return this;

    },

    setLoop: function( mode, repetitions ) {

        this.loop = mode;
        this.repetitions = repetitions;

        return this;

    },

    // Weight

    // set the weight stopping any scheduled fading
    // although .enabled = false yields an effective weight of zero, this
    // method does *not* change .enabled, because it would be confusing
    setEffectiveWeight: function( weight ) {

        this.weight = weight;

        // note: same logic as when updated at runtime
        this._effectiveWeight = this.enabled ? weight : 0;

        return this.stopFading();

    },

    // return the weight considering fading and .enabled
    getEffectiveWeight: function() {

        return this._effectiveWeight;

    },

    fadeIn: function( duration ) {

        return this._scheduleFading( duration, 0, 1 );

    },

    fadeOut: function( duration ) {

        return this._scheduleFading( duration, 1, 0 );

    },

    crossFadeFrom: function( fadeOutAction, duration, warp ) {

        fadeOutAction.fadeOut( duration );
        this.fadeIn( duration );

        if( warp ) {

            var fadeInDuration = this._clip.duration,
                fadeOutDuration = fadeOutAction._clip.duration,

                startEndRatio = fadeOutDuration / fadeInDuration,
                endStartRatio = fadeInDuration / fadeOutDuration;

            fadeOutAction.warp( 1.0, startEndRatio, duration );
            this.warp( endStartRatio, 1.0, duration );

        }

        return this;

    },

    crossFadeTo: function( fadeInAction, duration, warp ) {

        return fadeInAction.crossFadeFrom( this, duration, warp );

    },

    stopFading: function() {

        var weightInterpolant = this._weightInterpolant;

        if ( weightInterpolant !== null ) {

            this._weightInterpolant = null;
            this._mixer._takeBackControlInterpolant( weightInterpolant );

        }

        return this;

    },

    // Time Scale Control

    // set the time scale stopping any scheduled warping
    // although .paused = true yields an effective time scale of zero, this
    // method does *not* change .paused, because it would be confusing
    setEffectiveTimeScale: function( timeScale ) {

        this.timeScale = timeScale;
        this._effectiveTimeScale = this.paused ? 0 :timeScale;

        return this.stopWarping();

    },

    // return the time scale considering warping and .paused
    getEffectiveTimeScale: function() {

        return this._effectiveTimeScale;

    },

    setDuration: function( duration ) {

        this.timeScale = this._clip.duration / duration;

        return this.stopWarping();

    },

    syncWith: function( action ) {

        this.time = action.time;
        this.timeScale = action.timeScale;

        return this.stopWarping();

    },

    halt: function( duration ) {

        return this.warp( this._effectiveTimeScale, 0, duration );

    },

    warp: function( startTimeScale, endTimeScale, duration ) {

        var mixer = this._mixer, now = mixer.time,
            interpolant = this._timeScaleInterpolant,

            timeScale = this.timeScale;

        if ( interpolant === null ) {

            interpolant = mixer._lendControlInterpolant();
            this._timeScaleInterpolant = interpolant;

        }

        var times = interpolant.parameterPositions,
            values = interpolant.sampleValues;

        times[ 0 ] = now;
        times[ 1 ] = now + duration;

        values[ 0 ] = startTimeScale / timeScale;
        values[ 1 ] = endTimeScale / timeScale;

        return this;

    },

    stopWarping: function() {

        var timeScaleInterpolant = this._timeScaleInterpolant;

        if ( timeScaleInterpolant !== null ) {

            this._timeScaleInterpolant = null;
            this._mixer._takeBackControlInterpolant( timeScaleInterpolant );

        }

        return this;

    },

    // Object Accessors

    getMixer: function() {

        return this._mixer;

    },

    getClip: function() {

        return this._clip;

    },

    getRoot: function() {

        return this._localRoot || this._mixer._root;

    },

    // Interna

    _update: function( time, deltaTime, timeDirection, accuIndex ) {

        // called by the mixer

        if ( ! this.enabled ) {

            // call ._updateWeight() to update ._effectiveWeight

            this._updateWeight( time );
            return;

        }

        var startTime = this._startTime;

        if ( startTime !== null ) {

            // check for scheduled start of action

            var timeRunning = ( time - startTime ) * timeDirection;
            if ( timeRunning < 0 || timeDirection === 0 ) {

                return; // yet to come / don't decide when delta = 0

            }

            // start

            this._startTime = null; // unschedule
            deltaTime = timeDirection * timeRunning;

        }

        // apply time scale and advance time

        deltaTime *= this._updateTimeScale( time );
        var clipTime = this._updateTime( deltaTime );

        // note: _updateTime may disable the action resulting in
        // an effective weight of 0

        var weight = this._updateWeight( time );

        if ( weight > 0 ) {

            var interpolants = this._interpolants;
            var propertyMixers = this._propertyBindings;

            for ( var j = 0, m = interpolants.length; j !== m; ++ j ) {

                interpolants[ j ].evaluate( clipTime );
                propertyMixers[ j ].accumulate( accuIndex, weight );

            }

        }

    },

    _updateWeight: function( time ) {

        var weight = 0;

        if ( this.enabled ) {

            weight = this.weight;
            var interpolant = this._weightInterpolant;

            if ( interpolant !== null ) {

                var interpolantValue = interpolant.evaluate( time )[ 0 ];

                weight *= interpolantValue;

                if ( time > interpolant.parameterPositions[ 1 ] ) {

                    this.stopFading();

                    if ( interpolantValue === 0 ) {

                        // faded out, disable
                        this.enabled = false;

                    }

                }

            }

        }

        this._effectiveWeight = weight;
        return weight;

    },

    _updateTimeScale: function( time ) {

        var timeScale = 0;

        if ( ! this.paused ) {

            timeScale = this.timeScale;

            var interpolant = this._timeScaleInterpolant;

            if ( interpolant !== null ) {

                var interpolantValue = interpolant.evaluate( time )[ 0 ];

                timeScale *= interpolantValue;

                if ( time > interpolant.parameterPositions[ 1 ] ) {

                    this.stopWarping();

                    if ( timeScale === 0 ) {

                        // motion has halted, pause
                        this.paused = true;

                    } else {

                        // warp done - apply final time scale
                        this.timeScale = timeScale;

                    }

                }

            }

        }

        this._effectiveTimeScale = timeScale;
        return timeScale;

    },

    _updateTime: function( deltaTime ) {

        var time = this.time + deltaTime;

        if ( deltaTime === 0 ) return time;

        var duration = this._clip.duration,

            loop = this.loop,
            loopCount = this._loopCount;

        if ( loop === LoopOnce ) {

            if ( loopCount === -1 ) {
                // just started

                this._loopCount = 0;
                this._setEndings( true, true, false );

            }

            handle_stop: {

                if ( time >= duration ) {

                    time = duration;

                } else if ( time < 0 ) {

                    time = 0;

                } else break handle_stop;

                if ( this.clampWhenFinished ) this.paused = true;
                else this.enabled = false;

                this._mixer.dispatchEvent( {
                    type: 'finished', action: this,
                    direction: deltaTime < 0 ? -1 : 1
                } );

            }

        } else { // repetitive Repeat or PingPong

            var pingPong = ( loop === LoopPingPong );

            if ( loopCount === -1 ) {
                // just started

                if ( deltaTime >= 0 ) {

                    loopCount = 0;

                    this._setEndings(
                            true, this.repetitions === 0, pingPong );

                } else {

                    // when looping in reverse direction, the initial
                    // transition through zero counts as a repetition,
                    // so leave loopCount at -1

                    this._setEndings(
                            this.repetitions === 0, true, pingPong );

                }

            }

            if ( time >= duration || time < 0 ) {
                // wrap around

                var loopDelta = Math.floor( time / duration ); // signed
                time -= duration * loopDelta;

                loopCount += Math.abs( loopDelta );

                var pending = this.repetitions - loopCount;

                if ( pending < 0 ) {
                    // have to stop (switch state, clamp time, fire event)

                    if ( this.clampWhenFinished ) this.paused = true;
                    else this.enabled = false;

                    time = deltaTime > 0 ? duration : 0;

                    this._mixer.dispatchEvent( {
                        type: 'finished', action: this,
                        direction: deltaTime > 0 ? 1 : -1
                    } );

                } else {
                    // keep running

                    if ( pending === 0 ) {
                        // entering the last round

                        var atStart = deltaTime < 0;
                        this._setEndings( atStart, ! atStart, pingPong );

                    } else {

                        this._setEndings( false, false, pingPong );

                    }

                    this._loopCount = loopCount;

                    this._mixer.dispatchEvent( {
                        type: 'loop', action: this, loopDelta: loopDelta
                    } );

                }

            }

            if ( pingPong && ( loopCount & 1 ) === 1 ) {
                // invert time for the "pong round"

                this.time = time;
                return duration - time;

            }

        }

        this.time = time;
        return time;

    },

    _setEndings: function( atStart, atEnd, pingPong ) {

        var settings = this._interpolantSettings;

        if ( pingPong ) {

            settings.endingStart     = ZeroSlopeEnding;
            settings.endingEnd        = ZeroSlopeEnding;

        } else {

            // assuming for LoopOnce atStart == atEnd == true

            if ( atStart ) {

                settings.endingStart = this.zeroSlopeAtStart ?
                        ZeroSlopeEnding : ZeroCurvatureEnding;

            } else {

                settings.endingStart = WrapAroundEnding;

            }

            if ( atEnd ) {

                settings.endingEnd = this.zeroSlopeAtEnd ?
                        ZeroSlopeEnding : ZeroCurvatureEnding;

            } else {

                settings.endingEnd      = WrapAroundEnding;

            }

        }

    },

    _scheduleFading: function( duration, weightNow, weightThen ) {

        var mixer = this._mixer, now = mixer.time,
            interpolant = this._weightInterpolant;

        if ( interpolant === null ) {

            interpolant = mixer._lendControlInterpolant();
            this._weightInterpolant = interpolant;

        }

        var times = interpolant.parameterPositions,
            values = interpolant.sampleValues;

        times[ 0 ] = now;                 values[ 0 ] = weightNow;
        times[ 1 ] = now + duration;    values[ 1 ] = weightThen;

        return this;

    }

} );

/**
 *
 * Player for AnimationClips.
 *
 *
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
 * @author tschw
 */

function AnimationMixer( root ) {

    this._root = root;
    this._initMemoryManager();
    this._accuIndex = 0;

    this.time = 0;

    this.timeScale = 1.0;

}

Object.assign( AnimationMixer.prototype, EventDispatcher.prototype, {

    _bindAction: function ( action, prototypeAction ) {

        var root = action._localRoot || this._root,
            tracks = action._clip.tracks,
            nTracks = tracks.length,
            bindings = action._propertyBindings,
            interpolants = action._interpolants,
            rootUuid = root.uuid,
            bindingsByRoot = this._bindingsByRootAndName,
            bindingsByName = bindingsByRoot[ rootUuid ];

        if ( bindingsByName === undefined ) {

            bindingsByName = {};
            bindingsByRoot[ rootUuid ] = bindingsByName;

        }

        for ( var i = 0; i !== nTracks; ++ i ) {

            var track = tracks[ i ],
                trackName = track.name,
                binding = bindingsByName[ trackName ];

            if ( binding !== undefined ) {

                bindings[ i ] = binding;

            } else {

                binding = bindings[ i ];

                if ( binding !== undefined ) {

                    // existing binding, make sure the cache knows

                    if ( binding._cacheIndex === null ) {

                        ++ binding.referenceCount;
                        this._addInactiveBinding( binding, rootUuid, trackName );

                    }

                    continue;

                }

                var path = prototypeAction && prototypeAction.
                        _propertyBindings[ i ].binding.parsedPath;

                binding = new PropertyMixer(
                    PropertyBinding.create( root, trackName, path ),
                    track.ValueTypeName, track.getValueSize() );

                ++ binding.referenceCount;
                this._addInactiveBinding( binding, rootUuid, trackName );

                bindings[ i ] = binding;

            }

            interpolants[ i ].resultBuffer = binding.buffer;

        }

    },

    _activateAction: function ( action ) {

        if ( ! this._isActiveAction( action ) ) {

            if ( action._cacheIndex === null ) {

                // this action has been forgotten by the cache, but the user
                // appears to be still using it -> rebind

                var rootUuid = ( action._localRoot || this._root ).uuid,
                    clipUuid = action._clip.uuid,
                    actionsForClip = this._actionsByClip[ clipUuid ];

                this._bindAction( action,
                    actionsForClip && actionsForClip.knownActions[ 0 ] );

                this._addInactiveAction( action, clipUuid, rootUuid );

            }

            var bindings = action._propertyBindings;

            // increment reference counts / sort out state
            for ( var i = 0, n = bindings.length; i !== n; ++ i ) {

                var binding = bindings[ i ];

                if ( binding.useCount ++ === 0 ) {

                    this._lendBinding( binding );
                    binding.saveOriginalState();

                }

            }

            this._lendAction( action );

        }

    },

    _deactivateAction: function ( action ) {

        if ( this._isActiveAction( action ) ) {

            var bindings = action._propertyBindings;

            // decrement reference counts / sort out state
            for ( var i = 0, n = bindings.length; i !== n; ++ i ) {

                var binding = bindings[ i ];

                if ( -- binding.useCount === 0 ) {

                    binding.restoreOriginalState();
                    this._takeBackBinding( binding );

                }

            }

            this._takeBackAction( action );

        }

    },

    // Memory manager

    _initMemoryManager: function () {

        this._actions = []; // 'nActiveActions' followed by inactive ones
        this._nActiveActions = 0;

        this._actionsByClip = {};
        // inside:
        // {
        //         knownActions: Array< AnimationAction >    - used as prototypes
        //         actionByRoot: AnimationAction            - lookup
        // }


        this._bindings = []; // 'nActiveBindings' followed by inactive ones
        this._nActiveBindings = 0;

        this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >


        this._controlInterpolants = []; // same game as above
        this._nActiveControlInterpolants = 0;

        var scope = this;

        this.stats = {

            actions: {
                get total() { return scope._actions.length; },
                get inUse() { return scope._nActiveActions; }
            },
            bindings: {
                get total() { return scope._bindings.length; },
                get inUse() { return scope._nActiveBindings; }
            },
            controlInterpolants: {
                get total() { return scope._controlInterpolants.length; },
                get inUse() { return scope._nActiveControlInterpolants; }
            }

        };

    },

    // Memory management for AnimationAction objects

    _isActiveAction: function ( action ) {

        var index = action._cacheIndex;
        return index !== null && index < this._nActiveActions;

    },

    _addInactiveAction: function ( action, clipUuid, rootUuid ) {

        var actions = this._actions,
            actionsByClip = this._actionsByClip,
            actionsForClip = actionsByClip[ clipUuid ];

        if ( actionsForClip === undefined ) {

            actionsForClip = {

                knownActions: [ action ],
                actionByRoot: {}

            };

            action._byClipCacheIndex = 0;

            actionsByClip[ clipUuid ] = actionsForClip;

        } else {

            var knownActions = actionsForClip.knownActions;

            action._byClipCacheIndex = knownActions.length;
            knownActions.push( action );

        }

        action._cacheIndex = actions.length;
        actions.push( action );

        actionsForClip.actionByRoot[ rootUuid ] = action;

    },

    _removeInactiveAction: function ( action ) {

        var actions = this._actions,
            lastInactiveAction = actions[ actions.length - 1 ],
            cacheIndex = action._cacheIndex;

        lastInactiveAction._cacheIndex = cacheIndex;
        actions[ cacheIndex ] = lastInactiveAction;
        actions.pop();

        action._cacheIndex = null;


        var clipUuid = action._clip.uuid,
            actionsByClip = this._actionsByClip,
            actionsForClip = actionsByClip[ clipUuid ],
            knownActionsForClip = actionsForClip.knownActions,

            lastKnownAction =
                knownActionsForClip[ knownActionsForClip.length - 1 ],

            byClipCacheIndex = action._byClipCacheIndex;

        lastKnownAction._byClipCacheIndex = byClipCacheIndex;
        knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
        knownActionsForClip.pop();

        action._byClipCacheIndex = null;


        var actionByRoot = actionsForClip.actionByRoot,
            rootUuid = ( action._localRoot || this._root ).uuid;

        delete actionByRoot[ rootUuid ];

        if ( knownActionsForClip.length === 0 ) {

            delete actionsByClip[ clipUuid ];

        }

        this._removeInactiveBindingsForAction( action );

    },

    _removeInactiveBindingsForAction: function ( action ) {

        var bindings = action._propertyBindings;
        for ( var i = 0, n = bindings.length; i !== n; ++ i ) {

            var binding = bindings[ i ];

            if ( -- binding.referenceCount === 0 ) {

                this._removeInactiveBinding( binding );

            }

        }

    },

    _lendAction: function ( action ) {

        // [ active actions |  inactive actions  ]
        // [  active actions >| inactive actions ]
        //                 s        a
        //                  <-swap->
        //                 a        s

        var actions = this._actions,
            prevIndex = action._cacheIndex,

            lastActiveIndex = this._nActiveActions ++,

            firstInactiveAction = actions[ lastActiveIndex ];

        action._cacheIndex = lastActiveIndex;
        actions[ lastActiveIndex ] = action;

        firstInactiveAction._cacheIndex = prevIndex;
        actions[ prevIndex ] = firstInactiveAction;

    },

    _takeBackAction: function ( action ) {

        // [  active actions  | inactive actions ]
        // [ active actions |< inactive actions  ]
        //        a        s
        //         <-swap->
        //        s        a

        var actions = this._actions,
            prevIndex = action._cacheIndex,

            firstInactiveIndex = -- this._nActiveActions,

            lastActiveAction = actions[ firstInactiveIndex ];

        action._cacheIndex = firstInactiveIndex;
        actions[ firstInactiveIndex ] = action;

        lastActiveAction._cacheIndex = prevIndex;
        actions[ prevIndex ] = lastActiveAction;

    },

    // Memory management for PropertyMixer objects

    _addInactiveBinding: function ( binding, rootUuid, trackName ) {

        var bindingsByRoot = this._bindingsByRootAndName,
            bindingByName = bindingsByRoot[ rootUuid ],

            bindings = this._bindings;

        if ( bindingByName === undefined ) {

            bindingByName = {};
            bindingsByRoot[ rootUuid ] = bindingByName;

        }

        bindingByName[ trackName ] = binding;

        binding._cacheIndex = bindings.length;
        bindings.push( binding );

    },

    _removeInactiveBinding: function ( binding ) {

        var bindings = this._bindings,
            propBinding = binding.binding,
            rootUuid = propBinding.rootNode.uuid,
            trackName = propBinding.path,
            bindingsByRoot = this._bindingsByRootAndName,
            bindingByName = bindingsByRoot[ rootUuid ],

            lastInactiveBinding = bindings[ bindings.length - 1 ],
            cacheIndex = binding._cacheIndex;

        lastInactiveBinding._cacheIndex = cacheIndex;
        bindings[ cacheIndex ] = lastInactiveBinding;
        bindings.pop();

        delete bindingByName[ trackName ];

        remove_empty_map: {

            for ( var _ in bindingByName ) break remove_empty_map;

            delete bindingsByRoot[ rootUuid ];

        }

    },

    _lendBinding: function ( binding ) {

        var bindings = this._bindings,
            prevIndex = binding._cacheIndex,

            lastActiveIndex = this._nActiveBindings ++,

            firstInactiveBinding = bindings[ lastActiveIndex ];

        binding._cacheIndex = lastActiveIndex;
        bindings[ lastActiveIndex ] = binding;

        firstInactiveBinding._cacheIndex = prevIndex;
        bindings[ prevIndex ] = firstInactiveBinding;

    },

    _takeBackBinding: function ( binding ) {

        var bindings = this._bindings,
            prevIndex = binding._cacheIndex,

            firstInactiveIndex = -- this._nActiveBindings,

            lastActiveBinding = bindings[ firstInactiveIndex ];

        binding._cacheIndex = firstInactiveIndex;
        bindings[ firstInactiveIndex ] = binding;

        lastActiveBinding._cacheIndex = prevIndex;
        bindings[ prevIndex ] = lastActiveBinding;

    },


    // Memory management of Interpolants for weight and time scale

    _lendControlInterpolant: function () {

        var interpolants = this._controlInterpolants,
            lastActiveIndex = this._nActiveControlInterpolants ++,
            interpolant = interpolants[ lastActiveIndex ];

        if ( interpolant === undefined ) {

            interpolant = new LinearInterpolant(
                new Float32Array( 2 ), new Float32Array( 2 ),
                1, this._controlInterpolantsResultBuffer );

            interpolant.__cacheIndex = lastActiveIndex;
            interpolants[ lastActiveIndex ] = interpolant;

        }

        return interpolant;

    },

    _takeBackControlInterpolant: function ( interpolant ) {

        var interpolants = this._controlInterpolants,
            prevIndex = interpolant.__cacheIndex,

            firstInactiveIndex = -- this._nActiveControlInterpolants,

            lastActiveInterpolant = interpolants[ firstInactiveIndex ];

        interpolant.__cacheIndex = firstInactiveIndex;
        interpolants[ firstInactiveIndex ] = interpolant;

        lastActiveInterpolant.__cacheIndex = prevIndex;
        interpolants[ prevIndex ] = lastActiveInterpolant;

    },

    _controlInterpolantsResultBuffer: new Float32Array( 1 ),

    // return an action for a clip optionally using a custom root target
    // object (this method allocates a lot of dynamic memory in case a
    // previously unknown clip/root combination is specified)
    clipAction: function ( clip, optionalRoot ) {

        var root = optionalRoot || this._root,
            rootUuid = root.uuid,

            clipObject = typeof clip === 'string' ?
                AnimationClip.findByName( root, clip ) : clip,

            clipUuid = clipObject !== null ? clipObject.uuid : clip,

            actionsForClip = this._actionsByClip[ clipUuid ],
            prototypeAction = null;

        if ( actionsForClip !== undefined ) {

            var existingAction =
                    actionsForClip.actionByRoot[ rootUuid ];

            if ( existingAction !== undefined ) {

                return existingAction;

            }

            // we know the clip, so we don't have to parse all
            // the bindings again but can just copy
            prototypeAction = actionsForClip.knownActions[ 0 ];

            // also, take the clip from the prototype action
            if ( clipObject === null )
                clipObject = prototypeAction._clip;

        }

        // clip must be known when specified via string
        if ( clipObject === null ) return null;

        // allocate all resources required to run it
        var newAction = new AnimationAction( this, clipObject, optionalRoot );

        this._bindAction( newAction, prototypeAction );

        // and make the action known to the memory manager
        this._addInactiveAction( newAction, clipUuid, rootUuid );

        return newAction;

    },

    // get an existing action
    existingAction: function ( clip, optionalRoot ) {

        var root = optionalRoot || this._root,
            rootUuid = root.uuid,

            clipObject = typeof clip === 'string' ?
                AnimationClip.findByName( root, clip ) : clip,

            clipUuid = clipObject ? clipObject.uuid : clip,

            actionsForClip = this._actionsByClip[ clipUuid ];

        if ( actionsForClip !== undefined ) {

            return actionsForClip.actionByRoot[ rootUuid ] || null;

        }

        return null;

    },

    // deactivates all previously scheduled actions
    stopAllAction: function () {

        var actions = this._actions,
            nActions = this._nActiveActions,
            bindings = this._bindings,
            nBindings = this._nActiveBindings;

        this._nActiveActions = 0;
        this._nActiveBindings = 0;

        for ( var i = 0; i !== nActions; ++ i ) {

            actions[ i ].reset();

        }

        for ( var i = 0; i !== nBindings; ++ i ) {

            bindings[ i ].useCount = 0;

        }

        return this;

    },

    // advance the time and update apply the animation
    update: function ( deltaTime ) {

        deltaTime *= this.timeScale;

        var actions = this._actions,
            nActions = this._nActiveActions,

            time = this.time += deltaTime,
            timeDirection = Math.sign( deltaTime ),

            accuIndex = this._accuIndex ^= 1;

        // run active actions

        for ( var i = 0; i !== nActions; ++ i ) {

            var action = actions[ i ];

            action._update( time, deltaTime, timeDirection, accuIndex );

        }

        // update scene graph

        var bindings = this._bindings,
            nBindings = this._nActiveBindings;

        for ( var i = 0; i !== nBindings; ++ i ) {

            bindings[ i ].apply( accuIndex );

        }

        return this;

    },

    // return this mixer's root target object
    getRoot: function () {

        return this._root;

    },

    // free all resources specific to a particular clip
    uncacheClip: function ( clip ) {

        var actions = this._actions,
            clipUuid = clip.uuid,
            actionsByClip = this._actionsByClip,
            actionsForClip = actionsByClip[ clipUuid ];

        if ( actionsForClip !== undefined ) {

            // note: just calling _removeInactiveAction would mess up the
            // iteration state and also require updating the state we can
            // just throw away

            var actionsToRemove = actionsForClip.knownActions;

            for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {

                var action = actionsToRemove[ i ];

                this._deactivateAction( action );

                var cacheIndex = action._cacheIndex,
                    lastInactiveAction = actions[ actions.length - 1 ];

                action._cacheIndex = null;
                action._byClipCacheIndex = null;

                lastInactiveAction._cacheIndex = cacheIndex;
                actions[ cacheIndex ] = lastInactiveAction;
                actions.pop();

                this._removeInactiveBindingsForAction( action );

            }

            delete actionsByClip[ clipUuid ];

        }

    },

    // free all resources specific to a particular root target object
    uncacheRoot: function ( root ) {

        var rootUuid = root.uuid,
            actionsByClip = this._actionsByClip;

        for ( var clipUuid in actionsByClip ) {

            var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
                action = actionByRoot[ rootUuid ];

            if ( action !== undefined ) {

                this._deactivateAction( action );
                this._removeInactiveAction( action );

            }

        }

        var bindingsByRoot = this._bindingsByRootAndName,
            bindingByName = bindingsByRoot[ rootUuid ];

        if ( bindingByName !== undefined ) {

            for ( var trackName in bindingByName ) {

                var binding = bindingByName[ trackName ];
                binding.restoreOriginalState();
                this._removeInactiveBinding( binding );

            }

        }

    },

    // remove a targeted clip from the cache
    uncacheAction: function ( clip, optionalRoot ) {

        var action = this.existingAction( clip, optionalRoot );

        if ( action !== null ) {

            this._deactivateAction( action );
            this._removeInactiveAction( action );

        }

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Uniform( value ) {

    if ( typeof value === 'string' ) {

        console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
        value = arguments[ 1 ];

    }

    this.value = value;

}

Uniform.prototype.clone = function () {

    return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );

};

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 */

function InstancedBufferGeometry() {

    BufferGeometry.call( this );

    this.type = 'InstancedBufferGeometry';
    this.maxInstancedCount = undefined;

}

InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {

    constructor: InstancedBufferGeometry,

    isInstancedBufferGeometry: true,

    addGroup: function ( start, count, materialIndex ) {

        this.groups.push( {

            start: start,
            count: count,
            materialIndex: materialIndex

        } );

    },

    copy: function ( source ) {

        var index = source.index;

        if ( index !== null ) {

            this.setIndex( index.clone() );

        }

        var attributes = source.attributes;

        for ( var name in attributes ) {

            var attribute = attributes[ name ];
            this.addAttribute( name, attribute.clone() );

        }

        var groups = source.groups;

        for ( var i = 0, l = groups.length; i < l; i ++ ) {

            var group = groups[ i ];
            this.addGroup( group.start, group.count, group.materialIndex );

        }

        return this;

    }

} );

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 */

function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {

    this.uuid = _Math.generateUUID();

    this.data = interleavedBuffer;
    this.itemSize = itemSize;
    this.offset = offset;

    this.normalized = normalized === true;

}

Object.defineProperties( InterleavedBufferAttribute.prototype, {

    count: {

        get: function () {

            return this.data.count;

        }

    },

    array: {

        get: function () {

            return this.data.array;

        }

    }

} );

Object.assign( InterleavedBufferAttribute.prototype, {

    isInterleavedBufferAttribute: true,

    setX: function ( index, x ) {

        this.data.array[ index * this.data.stride + this.offset ] = x;

        return this;

    },

    setY: function ( index, y ) {

        this.data.array[ index * this.data.stride + this.offset + 1 ] = y;

        return this;

    },

    setZ: function ( index, z ) {

        this.data.array[ index * this.data.stride + this.offset + 2 ] = z;

        return this;

    },

    setW: function ( index, w ) {

        this.data.array[ index * this.data.stride + this.offset + 3 ] = w;

        return this;

    },

    getX: function ( index ) {

        return this.data.array[ index * this.data.stride + this.offset ];

    },

    getY: function ( index ) {

        return this.data.array[ index * this.data.stride + this.offset + 1 ];

    },

    getZ: function ( index ) {

        return this.data.array[ index * this.data.stride + this.offset + 2 ];

    },

    getW: function ( index ) {

        return this.data.array[ index * this.data.stride + this.offset + 3 ];

    },

    setXY: function ( index, x, y ) {

        index = index * this.data.stride + this.offset;

        this.data.array[ index + 0 ] = x;
        this.data.array[ index + 1 ] = y;

        return this;

    },

    setXYZ: function ( index, x, y, z ) {

        index = index * this.data.stride + this.offset;

        this.data.array[ index + 0 ] = x;
        this.data.array[ index + 1 ] = y;
        this.data.array[ index + 2 ] = z;

        return this;

    },

    setXYZW: function ( index, x, y, z, w ) {

        index = index * this.data.stride + this.offset;

        this.data.array[ index + 0 ] = x;
        this.data.array[ index + 1 ] = y;
        this.data.array[ index + 2 ] = z;
        this.data.array[ index + 3 ] = w;

        return this;

    }

} );

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 */

function InterleavedBuffer( array, stride ) {

    this.uuid = _Math.generateUUID();

    this.array = array;
    this.stride = stride;
    this.count = array !== undefined ? array.length / stride : 0;

    this.dynamic = false;
    this.updateRange = { offset: 0, count: - 1 };

    this.onUploadCallback = function () {};

    this.version = 0;

}

Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {

    set: function ( value ) {

        if ( value === true ) this.version ++;

    }

} );

Object.assign( InterleavedBuffer.prototype, {

    isInterleavedBuffer: true,

    setArray: function ( array ) {

        if ( Array.isArray( array ) ) {

            throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );

        }

        this.count = array !== undefined ? array.length / this.stride : 0;
        this.array = array;

    },

    setDynamic: function ( value ) {

        this.dynamic = value;

        return this;

    },

    copy: function ( source ) {

        this.array = new source.array.constructor( source.array );
        this.count = source.count;
        this.stride = source.stride;
        this.dynamic = source.dynamic;

        return this;

    },

    copyAt: function ( index1, attribute, index2 ) {

        index1 *= this.stride;
        index2 *= attribute.stride;

        for ( var i = 0, l = this.stride; 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;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    onUpload: function ( callback ) {

        this.onUploadCallback = callback;

        return this;

    }

} );

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 */

function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {

    InterleavedBuffer.call( this, array, stride );

    this.meshPerAttribute = meshPerAttribute || 1;

}

InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {

    constructor: InstancedInterleavedBuffer,

    isInstancedInterleavedBuffer: true,

    copy: function ( source ) {

        InterleavedBuffer.prototype.copy.call( this, source );

        this.meshPerAttribute = source.meshPerAttribute;

        return this;

    }

} );

/**
 * @author benaadams / https://twitter.com/ben_a_adams
 */

function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {

    BufferAttribute.call( this, array, itemSize );

    this.meshPerAttribute = meshPerAttribute || 1;

}

InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {

    constructor: InstancedBufferAttribute,

    isInstancedBufferAttribute: true,

    copy: function ( source ) {

        BufferAttribute.prototype.copy.call( this, source );

        this.meshPerAttribute = source.meshPerAttribute;

        return this;

    }

} );

/**
 * @author mrdoob / http://mrdoob.com/
 * @author bhouston / http://clara.io/
 * @author stephomi / http://stephaneginier.com/
 */

function Raycaster( origin, direction, near, far ) {

    this.ray = new Ray( origin, direction );
    // direction is assumed to be normalized (for accurate distance calculations)

    this.near = near || 0;
    this.far = far || Infinity;

    this.params = {
        Mesh: {},
        Line: {},
        LOD: {},
        Points: { threshold: 1 },
        Sprite: {}
    };

    Object.defineProperties( this.params, {
        PointCloud: {
            get: function () {
                console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
                return this.Points;
            }
        }
    } );

}

function ascSort( a, b ) {

    return a.distance - b.distance;

}

function intersectObject( object, raycaster, intersects, recursive ) {

    if ( object.visible === false ) return;

    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 );

        }

    }

}

Object.assign( Raycaster.prototype, {

    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 ) {

        if ( ( camera && camera.isPerspectiveCamera ) ) {

            this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
            this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();

        } else if ( ( camera && camera.isOrthographicCamera ) ) {

            this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
            this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );

        } else {

            console.error( 'THREE.Raycaster: Unsupported camera type.' );

        }

    },

    intersectObject: function ( object, recursive ) {

        var intersects = [];

        intersectObject( object, this, intersects, recursive );

        intersects.sort( ascSort );

        return intersects;

    },

    intersectObjects: function ( objects, recursive ) {

        var intersects = [];

        if ( Array.isArray( objects ) === false ) {

            console.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( ascSort );

        return intersects;

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 */

function Clock( autoStart ) {

    this.autoStart = ( autoStart !== undefined ) ? autoStart : true;

    this.startTime = 0;
    this.oldTime = 0;
    this.elapsedTime = 0;

    this.running = false;

}

Object.assign( Clock.prototype, {

    start: function () {

        this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732

        this.oldTime = this.startTime;
        this.elapsedTime = 0;
        this.running = true;

    },

    stop: function () {

        this.getElapsedTime();
        this.running = false;
        this.autoStart = false;

    },

    getElapsedTime: function () {

        this.getDelta();
        return this.elapsedTime;

    },

    getDelta: function () {

        var diff = 0;

        if ( this.autoStart && ! this.running ) {

            this.start();
            return 0;

        }

        if ( this.running ) {

            var newTime = ( typeof performance === 'undefined' ? Date : performance ).now();

            diff = ( newTime - this.oldTime ) / 1000;
            this.oldTime = newTime;

            this.elapsedTime += diff;

        }

        return diff;

    }

} );

/**
 * @author bhouston / http://clara.io
 * @author WestLangley / http://github.com/WestLangley
 *
 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
 *
 * The poles (phi) are at the positive and negative y axis.
 * The equator starts at positive z.
 */

function Spherical( radius, phi, theta ) {

    this.radius = ( radius !== undefined ) ? radius : 1.0;
    this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole
    this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere

    return this;

}

Object.assign( Spherical.prototype, {

    set: function ( radius, phi, theta ) {

        this.radius = radius;
        this.phi = phi;
        this.theta = theta;

        return this;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( other ) {

        this.radius = other.radius;
        this.phi = other.phi;
        this.theta = other.theta;

        return this;

    },

    // restrict phi to be betwee EPS and PI-EPS
    makeSafe: function() {

        var EPS = 0.000001;
        this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );

        return this;

    },

    setFromVector3: function( vec3 ) {

        this.radius = vec3.length();

        if ( this.radius === 0 ) {

            this.theta = 0;
            this.phi = 0;

        } else {

            this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis
            this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle

        }

        return this;

    }

} );

/**
 * @author Mugen87 / https://github.com/Mugen87
 *
 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
 *
 */

function Cylindrical( radius, theta, y ) {

    this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
    this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
    this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane

    return this;

}

Object.assign( Cylindrical.prototype, {

    set: function ( radius, theta, y ) {

        this.radius = radius;
        this.theta = theta;
        this.y = y;

        return this;

    },

    clone: function () {

        return new this.constructor().copy( this );

    },

    copy: function ( other ) {

        this.radius = other.radius;
        this.theta = other.theta;
        this.y = other.y;

        return this;

    },

    setFromVector3: function( vec3 ) {

        this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );
        this.theta = Math.atan2( vec3.x, vec3.z );
        this.y = vec3.y;

        return this;

    }

} );

/**
 * @author alteredq / http://alteredqualia.com/
 */

function MorphBlendMesh( geometry, material ) {

    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 );

}

MorphBlendMesh.prototype = Object.create( Mesh.prototype );
MorphBlendMesh.prototype.constructor = MorphBlendMesh;

MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) {

    var animation = {

        start: start,
        end: 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 );

};

MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {

    var pattern = /([a-z]+)_?(\d+)/i;

    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;

};

MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.direction = 1;
        animation.directionBackwards = false;

    }

};

MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.direction = - 1;
        animation.directionBackwards = true;

    }

};

MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.fps = fps;
        animation.duration = ( animation.end - animation.start ) / animation.fps;

    }

};

MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.duration = duration;
        animation.fps = ( animation.end - animation.start ) / animation.duration;

    }

};

MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.weight = weight;

    }

};

MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.time = time;

    }

};

MorphBlendMesh.prototype.getAnimationTime = function ( name ) {

    var time = 0;

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        time = animation.time;

    }

    return time;

};

MorphBlendMesh.prototype.getAnimationDuration = function ( name ) {

    var duration = - 1;

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        duration = animation.duration;

    }

    return duration;

};

MorphBlendMesh.prototype.playAnimation = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.time = 0;
        animation.active = true;

    } else {

        console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" );

    }

};

MorphBlendMesh.prototype.stopAnimation = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.active = false;

    }

};

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.start + _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;

        if ( animation.currentFrame !== animation.lastFrame ) {

            this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
            this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;

        } else {

            this.morphTargetInfluences[ animation.currentFrame ] = weight;

        }

    }

};

/**
 * @author alteredq / http://alteredqualia.com/
 */

function ImmediateRenderObject( material ) {

    Object3D.call( this );

    this.material = material;
    this.render = function ( renderCallback ) {};

}

ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;

ImmediateRenderObject.prototype.isImmediateRenderObject = true;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

function VertexNormalsHelper( 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 nNormals = 0;

    var objGeometry = this.object.geometry;

    if ( objGeometry && objGeometry.isGeometry ) {

        nNormals = objGeometry.faces.length * 3;

    } else if ( objGeometry && objGeometry.isBufferGeometry ) {

        nNormals = objGeometry.attributes.normal.count;

    }

    //

    var geometry = new BufferGeometry();

    var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );

    geometry.addAttribute( 'position', positions );

    LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );

    //

    this.matrixAutoUpdate = false;

    this.update();

}

VertexNormalsHelper.prototype = Object.create( LineSegments.prototype );
VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;

VertexNormalsHelper.prototype.update = ( function () {

    var v1 = new Vector3();
    var v2 = new Vector3();
    var normalMatrix = new Matrix3();

    return function update() {

        var keys = [ 'a', 'b', 'c' ];

        this.object.updateMatrixWorld( true );

        normalMatrix.getNormalMatrix( this.object.matrixWorld );

        var matrixWorld = this.object.matrixWorld;

        var position = this.geometry.attributes.position;

        //

        var objGeometry = this.object.geometry;

        if ( objGeometry && objGeometry.isGeometry ) {

            var vertices = objGeometry.vertices;

            var faces = objGeometry.faces;

            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 vertex = vertices[ face[ keys[ j ] ] ];

                    var normal = face.vertexNormals[ j ];

                    v1.copy( vertex ).applyMatrix4( matrixWorld );

                    v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );

                    position.setXYZ( idx, v1.x, v1.y, v1.z );

                    idx = idx + 1;

                    position.setXYZ( idx, v2.x, v2.y, v2.z );

                    idx = idx + 1;

                }

            }

        } else if ( objGeometry && objGeometry.isBufferGeometry ) {

            var objPos = objGeometry.attributes.position;

            var objNorm = objGeometry.attributes.normal;

            var idx = 0;

            // for simplicity, ignore index and drawcalls, and render every normal

            for ( var j = 0, jl = objPos.count; j < jl; j ++ ) {

                v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );

                v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );

                v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );

                position.setXYZ( idx, v1.x, v1.y, v1.z );

                idx = idx + 1;

                position.setXYZ( idx, v2.x, v2.y, v2.z );

                idx = idx + 1;

            }

        }

        position.needsUpdate = true;

    };

}() );

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

function SpotLightHelper( light ) {

    Object3D.call( this );

    this.light = light;
    this.light.updateMatrixWorld();

    this.matrix = light.matrixWorld;
    this.matrixAutoUpdate = false;

    var geometry = new BufferGeometry();

    var positions = [
        0, 0, 0,   0,   0,   1,
        0, 0, 0,   1,   0,   1,
        0, 0, 0, - 1,   0,   1,
        0, 0, 0,   0,   1,   1,
        0, 0, 0,   0, - 1,   1
    ];

    for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {

        var p1 = ( i / l ) * Math.PI * 2;
        var p2 = ( j / l ) * Math.PI * 2;

        positions.push(
            Math.cos( p1 ), Math.sin( p1 ), 1,
            Math.cos( p2 ), Math.sin( p2 ), 1
        );

    }

    geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );

    var material = new LineBasicMaterial( { fog: false } );

    this.cone = new LineSegments( geometry, material );
    this.add( this.cone );

    this.update();

}

SpotLightHelper.prototype = Object.create( Object3D.prototype );
SpotLightHelper.prototype.constructor = SpotLightHelper;

SpotLightHelper.prototype.dispose = function () {

    this.cone.geometry.dispose();
    this.cone.material.dispose();

};

SpotLightHelper.prototype.update = function () {

    var vector = new Vector3();
    var vector2 = new Vector3();

    return function update() {

        this.light.updateMatrixWorld();

        var coneLength = this.light.distance ? this.light.distance : 1000;
        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 );

    };

}();

/**
 * @author Sean Griffin / http://twitter.com/sgrif
 * @author Michael Guerrero / http://realitymeltdown.com
 * @author mrdoob / http://mrdoob.com/
 * @author ikerr / http://verold.com
 * @author Mugen87 / https://github.com/Mugen87
 */

function getBoneList( object ) {

    var boneList = [];

    if ( object && object.isBone ) {

        boneList.push( object );

    }

    for ( var i = 0; i < object.children.length; i ++ ) {

        boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );

    }

    return boneList;

}

function SkeletonHelper( object ) {

    var bones = getBoneList( object );

    var geometry = new BufferGeometry();

    var vertices = [];
    var colors = [];

    var color1 = new Color( 0, 0, 1 );
    var color2 = new Color( 0, 1, 0 );

    for ( var i = 0; i < bones.length; i ++ ) {

        var bone = bones[ i ];

        if ( bone.parent && bone.parent.isBone ) {

            vertices.push( 0, 0, 0 );
            vertices.push( 0, 0, 0 );
            colors.push( color1.r, color1.g, color1.b );
            colors.push( color2.r, color2.g, color2.b );

        }

    }

    geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );

    var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );

    LineSegments.call( this, geometry, material );

    this.root = object;
    this.bones = bones;

    this.matrix = object.matrixWorld;
    this.matrixAutoUpdate = false;

    this.onBeforeRender();

}

SkeletonHelper.prototype = Object.create( LineSegments.prototype );
SkeletonHelper.prototype.constructor = SkeletonHelper;

SkeletonHelper.prototype.onBeforeRender = function () {

    var vector = new Vector3();

    var boneMatrix = new Matrix4();
    var matrixWorldInv = new Matrix4();

    return function onBeforeRender() {

        var bones = this.bones;

        var geometry = this.geometry;
        var position = geometry.getAttribute( 'position' );

        matrixWorldInv.getInverse( this.root.matrixWorld );

        for ( var i = 0, j = 0; i < bones.length; i ++ ) {

            var bone = bones[ i ];

            if ( bone.parent && bone.parent.isBone ) {

                boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
                vector.setFromMatrixPosition( boneMatrix );
                position.setXYZ( j, vector.x, vector.y, vector.z );

                boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
                vector.setFromMatrixPosition( boneMatrix );
                position.setXYZ( j + 1, vector.x, vector.y, vector.z );

                j += 2;

            }

        }

        geometry.getAttribute( 'position' ).needsUpdate = true;

    };

}();

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

function PointLightHelper( light, sphereSize ) {

    this.light = light;
    this.light.updateMatrixWorld();

    var geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
    var material = new MeshBasicMaterial( { wireframe: true, fog: false } );
    material.color.copy( this.light.color );

    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 );
    */

}

PointLightHelper.prototype = Object.create( Mesh.prototype );
PointLightHelper.prototype.constructor = PointLightHelper;

PointLightHelper.prototype.dispose = function () {

    this.geometry.dispose();
    this.material.dispose();

};

PointLightHelper.prototype.update = function () {

    this.material.color.copy( this.light.color );

    /*
    var d = this.light.distance;

    if ( d === 0.0 ) {

        this.lightDistance.visible = false;

    } else {

        this.lightDistance.visible = true;
        this.lightDistance.scale.set( d, d, d );

    }
    */

};

/**
 * @author abelnation / http://github.com/abelnation
 * @author Mugen87 / http://github.com/Mugen87
 * @author WestLangley / http://github.com/WestLangley
 */

function RectAreaLightHelper( light ) {

    Object3D.call( this );

    this.light = light;
    this.light.updateMatrixWorld();

    this.matrix = light.matrixWorld;
    this.matrixAutoUpdate = false;

    var material = new LineBasicMaterial( { color: light.color } );

    var geometry = new BufferGeometry();

    geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) );

    this.add( new Line( geometry, material ) );

    this.update();

}

RectAreaLightHelper.prototype = Object.create( Object3D.prototype );
RectAreaLightHelper.prototype.constructor = RectAreaLightHelper;

RectAreaLightHelper.prototype.dispose = function () {

    this.children[ 0 ].geometry.dispose();
    this.children[ 0 ].material.dispose();

};

RectAreaLightHelper.prototype.update = function () {

    var line = this.children[ 0 ];

    // update material

    line.material.color.copy( this.light.color );

    // calculate new dimensions of the helper

    var hx = this.light.width * 0.5;
    var hy = this.light.height * 0.5;

    var position = line.geometry.attributes.position;
    var array = position.array;

    // update vertices

    array[  0 ] =   hx; array[  1 ] = - hy; array[  2 ] = 0;
    array[  3 ] =   hx; array[  4 ] =   hy; array[  5 ] = 0;
    array[  6 ] = - hx; array[  7 ] =   hy; array[  8 ] = 0;
    array[  9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0;
    array[ 12 ] =   hx; array[ 13 ] = - hy; array[ 14 ] = 0;

    position.needsUpdate = true;

};

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / https://github.com/Mugen87
 */

function HemisphereLightHelper( light, size ) {

    Object3D.call( this );

    this.light = light;
    this.light.updateMatrixWorld();

    this.matrix = light.matrixWorld;
    this.matrixAutoUpdate = false;

    var geometry = new OctahedronBufferGeometry( size );
    geometry.rotateY( Math.PI * 0.5 );

    var material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } );

    var position = geometry.getAttribute( 'position' );
    var colors = new Float32Array( position.count * 3 );

    geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );

    this.add( new Mesh( geometry, material ) );

    this.update();

}

HemisphereLightHelper.prototype = Object.create( Object3D.prototype );
HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;

HemisphereLightHelper.prototype.dispose = function () {

    this.children[ 0 ].geometry.dispose();
    this.children[ 0 ].material.dispose();

};

HemisphereLightHelper.prototype.update = function () {

    var vector = new Vector3();

    var color1 = new Color();
    var color2 = new Color();

    return function update() {

        var mesh = this.children[ 0 ];

        var colors = mesh.geometry.getAttribute( 'color' );

        color1.copy( this.light.color );
        color2.copy( this.light.groundColor );

        for ( var i = 0, l = colors.count; i < l; i ++ ) {

            var color = ( i < ( l / 2 ) ) ? color1 : color2;

            colors.setXYZ( i, color.r, color.g, color.b );

        }

        mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );

        colors.needsUpdate = true;

    };

}();

/**
 * @author mrdoob / http://mrdoob.com/
 */

function GridHelper( size, divisions, color1, color2 ) {

    size = size || 10;
    divisions = divisions || 10;
    color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
    color2 = new Color( color2 !== undefined ? color2 : 0x888888 );

    var center = divisions / 2;
    var step = size / divisions;
    var halfSize = size / 2;

    var vertices = [], colors = [];

    for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {

        vertices.push( - halfSize, 0, k, halfSize, 0, k );
        vertices.push( k, 0, - halfSize, k, 0, halfSize );

        var color = i === center ? color1 : color2;

        color.toArray( colors, j ); j += 3;
        color.toArray( colors, j ); j += 3;
        color.toArray( colors, j ); j += 3;
        color.toArray( colors, j ); j += 3;

    }

    var geometry = new BufferGeometry();
    geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );

    var material = new LineBasicMaterial( { vertexColors: VertexColors } );

    LineSegments.call( this, geometry, material );

}

GridHelper.prototype = Object.create( LineSegments.prototype );
GridHelper.prototype.constructor = GridHelper;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / http://github.com/Mugen87
 * @author Hectate / http://www.github.com/Hectate
 */

function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {

    radius = radius || 10;
    radials = radials || 16;
    circles = circles || 8;
    divisions = divisions || 64;
    color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
    color2 = new Color( color2 !== undefined ? color2 : 0x888888 );

    var vertices = [];
    var colors = [];

    var x, z;
    var v, i, j, r, color;

    // create the radials

    for ( i = 0; i <= radials; i ++ ) {

        v = ( i / radials ) * ( Math.PI * 2 );

        x = Math.sin( v ) * radius;
        z = Math.cos( v ) * radius;

        vertices.push( 0, 0, 0 );
        vertices.push( x, 0, z );

        color = ( i & 1 ) ? color1 : color2;

        colors.push( color.r, color.g, color.b );
        colors.push( color.r, color.g, color.b );

    }

    // create the circles

    for ( i = 0; i <= circles; i ++ ) {

        color = ( i & 1 ) ? color1 : color2;

        r = radius - ( radius / circles * i );

        for ( j = 0; j < divisions; j ++ ) {

            // first vertex

            v = ( j / divisions ) * ( Math.PI * 2 );

            x = Math.sin( v ) * r;
            z = Math.cos( v ) * r;

            vertices.push( x, 0, z );
            colors.push( color.r, color.g, color.b );

            // second vertex

            v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );

            x = Math.sin( v ) * r;
            z = Math.cos( v ) * r;

            vertices.push( x, 0, z );
            colors.push( color.r, color.g, color.b );

        }

    }

    var geometry = new BufferGeometry();
    geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );

    var material = new LineBasicMaterial( { vertexColors: VertexColors } );

    LineSegments.call( this, geometry, material );

}

PolarGridHelper.prototype = Object.create( LineSegments.prototype );
PolarGridHelper.prototype.constructor = PolarGridHelper;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
*/

function FaceNormalsHelper( object, size, hex, linewidth ) {

    // FaceNormalsHelper only supports THREE.Geometry

    this.object = object;

    this.size = ( size !== undefined ) ? size : 1;

    var color = ( hex !== undefined ) ? hex : 0xffff00;

    var width = ( linewidth !== undefined ) ? linewidth : 1;

    //

    var nNormals = 0;

    var objGeometry = this.object.geometry;

    if ( objGeometry && objGeometry.isGeometry ) {

        nNormals = objGeometry.faces.length;

    } else {

        console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );

    }

    //

    var geometry = new BufferGeometry();

    var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );

    geometry.addAttribute( 'position', positions );

    LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );

    //

    this.matrixAutoUpdate = false;
    this.update();

}

FaceNormalsHelper.prototype = Object.create( LineSegments.prototype );
FaceNormalsHelper.prototype.constructor = FaceNormalsHelper;

FaceNormalsHelper.prototype.update = ( function () {

    var v1 = new Vector3();
    var v2 = new Vector3();
    var normalMatrix = new Matrix3();

    return function update() {

        this.object.updateMatrixWorld( true );

        normalMatrix.getNormalMatrix( this.object.matrixWorld );

        var matrixWorld = this.object.matrixWorld;

        var position = this.geometry.attributes.position;

        //

        var objGeometry = this.object.geometry;

        var vertices = objGeometry.vertices;

        var faces = objGeometry.faces;

        var idx = 0;

        for ( var i = 0, l = faces.length; i < l; i ++ ) {

            var face = faces[ i ];

            var normal = face.normal;

            v1.copy( vertices[ face.a ] )
                .add( vertices[ face.b ] )
                .add( vertices[ face.c ] )
                .divideScalar( 3 )
                .applyMatrix4( matrixWorld );

            v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );

            position.setXYZ( idx, v1.x, v1.y, v1.z );

            idx = idx + 1;

            position.setXYZ( idx, v2.x, v2.y, v2.z );

            idx = idx + 1;

        }

        position.needsUpdate = true;

    };

}() );

/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author WestLangley / http://github.com/WestLangley
 */

function DirectionalLightHelper( light, size ) {

    Object3D.call( this );

    this.light = light;
    this.light.updateMatrixWorld();

    this.matrix = light.matrixWorld;
    this.matrixAutoUpdate = false;

    if ( size === undefined ) size = 1;

    var geometry = new BufferGeometry();
    geometry.addAttribute( 'position', new Float32BufferAttribute( [
        - size,   size, 0,
          size,   size, 0,
          size, - size, 0,
        - size, - size, 0,
        - size,   size, 0
    ], 3 ) );

    var material = new LineBasicMaterial( { fog: false } );

    this.add( new Line( geometry, material ) );

    geometry = new BufferGeometry();
    geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );

    this.add( new Line( geometry, material ));

    this.update();

}

DirectionalLightHelper.prototype = Object.create( Object3D.prototype );
DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;

DirectionalLightHelper.prototype.dispose = function () {

    var lightPlane = this.children[ 0 ];
    var targetLine = this.children[ 1 ];

    lightPlane.geometry.dispose();
    lightPlane.material.dispose();
    targetLine.geometry.dispose();
    targetLine.material.dispose();

};

DirectionalLightHelper.prototype.update = function () {

    var v1 = new Vector3();
    var v2 = new Vector3();
    var v3 = new Vector3();

    return function update() {

        v1.setFromMatrixPosition( this.light.matrixWorld );
        v2.setFromMatrixPosition( this.light.target.matrixWorld );
        v3.subVectors( v2, v1 );

        var lightPlane = this.children[ 0 ];
        var targetLine = this.children[ 1 ];

        lightPlane.lookAt( v3 );
        lightPlane.material.color.copy( this.light.color );

        targetLine.lookAt( v3 );
        targetLine.scale.z = v3.length();

    };

}();

/**
 * @author alteredq / http://alteredqualia.com/
 * @author Mugen87 / https://github.com/Mugen87
 *
 *    - 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
 */

function CameraHelper( camera ) {

    var geometry = new BufferGeometry();
    var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );

    var vertices = [];
    var colors = [];

    var pointMap = {};

    // colors

    var colorFrustum = new Color( 0xffaa00 );
    var colorCone = new Color( 0xff0000 );
    var colorUp = new Color( 0x00aaff );
    var colorTarget = new Color( 0xffffff );
    var colorCross = new Color( 0x333333 );

    // near

    addLine( "n1", "n2", colorFrustum );
    addLine( "n2", "n4", colorFrustum );
    addLine( "n4", "n3", colorFrustum );
    addLine( "n3", "n1", colorFrustum );

    // far

    addLine( "f1", "f2", colorFrustum );
    addLine( "f2", "f4", colorFrustum );
    addLine( "f4", "f3", colorFrustum );
    addLine( "f3", "f1", colorFrustum );

    // sides

    addLine( "n1", "f1", colorFrustum );
    addLine( "n2", "f2", colorFrustum );
    addLine( "n3", "f3", colorFrustum );
    addLine( "n4", "f4", colorFrustum );

    // cone

    addLine( "p", "n1", colorCone );
    addLine( "p", "n2", colorCone );
    addLine( "p", "n3", colorCone );
    addLine( "p", "n4", colorCone );

    // up

    addLine( "u1", "u2", colorUp );
    addLine( "u2", "u3", colorUp );
    addLine( "u3", "u1", colorUp );

    // target

    addLine( "c", "t", colorTarget );
    addLine( "p", "c", colorCross );

    // cross

    addLine( "cn1", "cn2", colorCross );
    addLine( "cn3", "cn4", colorCross );

    addLine( "cf1", "cf2", colorCross );
    addLine( "cf3", "cf4", colorCross );

    function addLine( a, b, color ) {

        addPoint( a, color );
        addPoint( b, color );

    }

    function addPoint( id, color ) {

        vertices.push( 0, 0, 0 );
        colors.push( color.r, color.g, color.b );

        if ( pointMap[ id ] === undefined ) {

            pointMap[ id ] = [];

        }

        pointMap[ id ].push( ( vertices.length / 3 ) - 1 );

    }

    geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );

    LineSegments.call( this, geometry, material );

    this.camera = camera;
    if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();

    this.matrix = camera.matrixWorld;
    this.matrixAutoUpdate = false;

    this.pointMap = pointMap;

    this.update();

}

CameraHelper.prototype = Object.create( LineSegments.prototype );
CameraHelper.prototype.constructor = CameraHelper;

CameraHelper.prototype.update = function () {

    var geometry, pointMap;

    var vector = new Vector3();
    var camera = new Camera();

    function setPoint( point, x, y, z ) {

        vector.set( x, y, z ).unproject( camera );

        var points = pointMap[ point ];

        if ( points !== undefined ) {

            var position = geometry.getAttribute( 'position' );

            for ( var i = 0, l = points.length; i < l; i ++ ) {

                position.setXYZ( points[ i ], vector.x, vector.y, vector.z );

            }

        }

    }

    return function update() {

        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.getAttribute( 'position' ).needsUpdate = true;

    };

}();

/**
 * @author mrdoob / http://mrdoob.com/
 * @author Mugen87 / http://github.com/Mugen87
 */

function BoxHelper( object, color ) {

    this.object = object;

    if ( color === undefined ) color = 0xffff00;

    var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
    var positions = new Float32Array( 8 * 3 );

    var geometry = new BufferGeometry();
    geometry.setIndex( new BufferAttribute( indices, 1 ) );
    geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );

    LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );

    this.matrixAutoUpdate = false;

    this.update();

}

BoxHelper.prototype = Object.create( LineSegments.prototype );
BoxHelper.prototype.constructor = BoxHelper;

BoxHelper.prototype.update = ( function () {

    var box = new Box3();

    return function update( object ) {

        if ( object !== undefined ) {

            console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );

        }

        if ( this.object !== undefined ) {

            box.setFromObject( this.object );

        }

        if ( box.isEmpty() ) return;

        var min = box.min;
        var max = box.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 position = this.geometry.attributes.position;
        var array = position.array;

        array[  0 ] = max.x; array[  1 ] = max.y; array[  2 ] = max.z;
        array[  3 ] = min.x; array[  4 ] = max.y; array[  5 ] = max.z;
        array[  6 ] = min.x; array[  7 ] = min.y; array[  8 ] = max.z;
        array[  9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
        array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
        array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
        array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
        array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;

        position.needsUpdate = true;

        this.geometry.computeBoundingSphere();

    };

} )();

BoxHelper.prototype.setFromObject = function ( object ) {

    this.object = object;
    this.update();

    return this;

};

/**
 * @author WestLangley / http://github.com/WestLangley
 * @author zz85 / http://github.com/zz85
 * @author bhouston / http://clara.io
 *
 * Creates an arrow for visualizing directions
 *
 * Parameters:
 *  dir - Vector3
 *  origin - Vector3
 *  length - Number
 *  color - color in hex value
 *  headLength - Number
 *  headWidth - Number
 */

var lineGeometry;
var coneGeometry;

function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {

    // dir is assumed to be normalized

    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;

    if ( lineGeometry === undefined ) {

        lineGeometry = new BufferGeometry();
        lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );

        coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
        coneGeometry.translate( 0, - 0.5, 0 );

    }

    this.position.copy( origin );

    this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );
    this.line.matrixAutoUpdate = false;
    this.add( this.line );

    this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );
    this.cone.matrixAutoUpdate = false;
    this.add( this.cone );

    this.setDirection( dir );
    this.setLength( length, headLength, headWidth );

}

ArrowHelper.prototype = Object.create( Object3D.prototype );
ArrowHelper.prototype.constructor = ArrowHelper;

ArrowHelper.prototype.setDirection = ( function () {

    var axis = new Vector3();
    var radians;

    return function setDirection( 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 );

        }

    };

}() );

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, Math.max( 0, length - headLength ), 1 );
    this.line.updateMatrix();

    this.cone.scale.set( headWidth, headLength, headWidth );
    this.cone.position.y = length;
    this.cone.updateMatrix();

};

ArrowHelper.prototype.setColor = function ( color ) {

    this.line.material.color.copy( color );
    this.cone.material.color.copy( color );

};

/**
 * @author sroucheray / http://sroucheray.org/
 * @author mrdoob / http://mrdoob.com/
 */

function AxisHelper( size ) {

    size = size || 1;

    var vertices = [
        0, 0, 0,  size, 0, 0,
        0, 0, 0,  0, size, 0,
        0, 0, 0,  0, 0, size
    ];

    var colors = [
        1, 0, 0,  1, 0.6, 0,
        0, 1, 0,  0.6, 1, 0,
        0, 0, 1,  0, 0.6, 1
    ];

    var geometry = new BufferGeometry();
    geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );

    var material = new LineBasicMaterial( { vertexColors: VertexColors } );

    LineSegments.call( this, geometry, material );

}

AxisHelper.prototype = Object.create( LineSegments.prototype );
AxisHelper.prototype.constructor = AxisHelper;

/**
 * @author zz85 https://github.com/zz85
 *
 * Centripetal CatmullRom Curve - which is useful for avoiding
 * cusps and self-intersections in non-uniform catmull rom curves.
 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
 *
 * curve.type accepts centripetal(default), chordal and catmullrom
 * curve.tension is used for catmullrom which defaults to 0.5
 */


/*
Based on an optimized c++ solution in
 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
 - http://ideone.com/NoEbVM

This CubicPoly class could be used for reusing some variables and calculations,
but for three.js curve use, it could be possible inlined and flatten into a single function call
which can be placed in CurveUtils.
*/

function CubicPoly() {

    var c0 = 0, c1 = 0, c2 = 0, c3 = 0;

    /*
     * Compute coefficients for a cubic polynomial
     *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
     * such that
     *   p(0) = x0, p(1) = x1
     *  and
     *   p'(0) = t0, p'(1) = t1.
     */
    function init( x0, x1, t0, t1 ) {

        c0 = x0;
        c1 = t0;
        c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
        c3 = 2 * x0 - 2 * x1 + t0 + t1;

    }

    return {

        initCatmullRom: function ( x0, x1, x2, x3, tension ) {

            init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );

        },

        initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {

            // compute tangents when parameterized in [t1,t2]
            var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
            var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;

            // rescale tangents for parametrization in [0,1]
            t1 *= dt1;
            t2 *= dt1;

            init( x1, x2, t1, t2 );

        },

        calc: function ( t ) {

            var t2 = t * t;
            var t3 = t2 * t;
            return c0 + c1 * t + c2 * t2 + c3 * t3;

        }

    };

}

//

var tmp = new Vector3();
var px = new CubicPoly();
var py = new CubicPoly();
var pz = new CubicPoly();

function CatmullRomCurve3( points ) {

    Curve.call( this );

    if ( points.length < 2 ) console.warn( 'THREE.CatmullRomCurve3: Points array needs at least two entries.' );

    this.points = points || [];
    this.closed = false;

}

CatmullRomCurve3.prototype = Object.create( Curve.prototype );
CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;

CatmullRomCurve3.prototype.getPoint = function ( t ) {

    var points = this.points;
    var l = points.length;

    var point = ( l - ( this.closed ? 0 : 1 ) ) * t;
    var intPoint = Math.floor( point );
    var weight = point - intPoint;

    if ( this.closed ) {

        intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;

    } else if ( weight === 0 && intPoint === l - 1 ) {

        intPoint = l - 2;
        weight = 1;

    }

    var p0, p1, p2, p3; // 4 points

    if ( this.closed || intPoint > 0 ) {

        p0 = points[ ( intPoint - 1 ) % l ];

    } else {

        // extrapolate first point
        tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
        p0 = tmp;

    }

    p1 = points[ intPoint % l ];
    p2 = points[ ( intPoint + 1 ) % l ];

    if ( this.closed || intPoint + 2 < l ) {

        p3 = points[ ( intPoint + 2 ) % l ];

    } else {

        // extrapolate last point
        tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
        p3 = tmp;

    }

    if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {

        // init Centripetal / Chordal Catmull-Rom
        var pow = this.type === 'chordal' ? 0.5 : 0.25;
        var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
        var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
        var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );

        // safety check for repeated points
        if ( dt1 < 1e-4 ) dt1 = 1.0;
        if ( dt0 < 1e-4 ) dt0 = dt1;
        if ( dt2 < 1e-4 ) dt2 = dt1;

        px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
        py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
        pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );

    } else if ( this.type === 'catmullrom' ) {

        var tension = this.tension !== undefined ? this.tension : 0.5;
        px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );
        py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );
        pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );

    }

    return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) );

};

function CubicBezierCurve3( v0, v1, v2, v3 ) {

    Curve.call( this );

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;
    this.v3 = v3;

}

CubicBezierCurve3.prototype = Object.create( Curve.prototype );
CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;

CubicBezierCurve3.prototype.getPoint = function ( t ) {

    var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;

    return new Vector3(
        CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
        CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
        CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
    );

};

function QuadraticBezierCurve3( v0, v1, v2 ) {

    Curve.call( this );

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;

}

QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;

QuadraticBezierCurve3.prototype.getPoint = function ( t ) {

    var v0 = this.v0, v1 = this.v1, v2 = this.v2;

    return new Vector3(
        QuadraticBezier( t, v0.x, v1.x, v2.x ),
        QuadraticBezier( t, v0.y, v1.y, v2.y ),
        QuadraticBezier( t, v0.z, v1.z, v2.z )
    );

};

function LineCurve3( v1, v2 ) {

    Curve.call( this );

    this.v1 = v1;
    this.v2 = v2;

}

LineCurve3.prototype = Object.create( Curve.prototype );
LineCurve3.prototype.constructor = LineCurve3;

LineCurve3.prototype.getPoint = function ( t ) {

    if ( t === 1 ) {

        return this.v2.clone();

    }

    var vector = new Vector3();

    vector.subVectors( this.v2, this.v1 ); // diff
    vector.multiplyScalar( t );
    vector.add( this.v1 );

    return vector;

};

function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {

    EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );

}

ArcCurve.prototype = Object.create( EllipseCurve.prototype );
ArcCurve.prototype.constructor = ArcCurve;

/**
 * @author alteredq / http://alteredqualia.com/
 */

var SceneUtils = {

    createMultiMaterialObject: function ( geometry, materials ) {

        var group = new Group();

        for ( var i = 0, l = materials.length; i < l; i ++ ) {

            group.add( new 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 ) {

        child.applyMatrix( new Matrix4().getInverse( parent.matrixWorld ) );

        scene.remove( child );
        parent.add( child );

    }

};

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Face4( a, b, c, d, normal, color, materialIndex ) {

    console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
    return new Face3( a, b, c, normal, color, materialIndex );

}

var LineStrip = 0;

var LinePieces = 1;

function MeshFaceMaterial( materials ) {

    console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );
    return materials;

}

function MultiMaterial( materials ) {

    if ( materials === undefined ) materials = [];

    console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );
    materials.isMultiMaterial = true;
    materials.materials = materials;
    materials.clone = function () {

        return materials.slice();

    };
    return materials;

}

function PointCloud( geometry, material ) {

    console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
    return new Points( geometry, material );

}

function Particle( material ) {

    console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
    return new Sprite( material );

}

function ParticleSystem( geometry, material ) {

    console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
    return new Points( geometry, material );

}

function PointCloudMaterial( parameters ) {

    console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
    return new PointsMaterial( parameters );

}

function ParticleBasicMaterial( parameters ) {

    console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
    return new PointsMaterial( parameters );

}

function ParticleSystemMaterial( parameters ) {

    console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
    return new PointsMaterial( parameters );

}

function Vertex( x, y, z ) {

    console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
    return new Vector3( x, y, z );

}

//

function DynamicBufferAttribute( array, itemSize ) {

    console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' );
    return new BufferAttribute( array, itemSize ).setDynamic( true );

}

function Int8Attribute( array, itemSize ) {

    console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
    return new Int8BufferAttribute( array, itemSize );

}

function Uint8Attribute( array, itemSize ) {

    console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
    return new Uint8BufferAttribute( array, itemSize );

}

function Uint8ClampedAttribute( array, itemSize ) {

    console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
    return new Uint8ClampedBufferAttribute( array, itemSize );

}

function Int16Attribute( array, itemSize ) {

    console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
    return new Int16BufferAttribute( array, itemSize );

}

function Uint16Attribute( array, itemSize ) {

    console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
    return new Uint16BufferAttribute( array, itemSize );

}

function Int32Attribute( array, itemSize ) {

    console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
    return new Int32BufferAttribute( array, itemSize );

}

function Uint32Attribute( array, itemSize ) {

    console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
    return new Uint32BufferAttribute( array, itemSize );

}

function Float32Attribute( array, itemSize ) {

    console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
    return new Float32BufferAttribute( array, itemSize );

}

function Float64Attribute( array, itemSize ) {

    console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
    return new Float64BufferAttribute( array, itemSize );

}

//

Curve.create = function ( construct, getPoint ) {

    console.log( 'THREE.Curve.create() has been deprecated' );

    construct.prototype = Object.create( Curve.prototype );
    construct.prototype.constructor = construct;
    construct.prototype.getPoint = getPoint;

    return construct;

};

//

function ClosedSplineCurve3( points ) {

    console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );

    CatmullRomCurve3.call( this, points );
    this.type = 'catmullrom';
    this.closed = true;

}

ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );

//

function SplineCurve3( points ) {

    console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );

    CatmullRomCurve3.call( this, points );
    this.type = 'catmullrom';

}

SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );

//

function Spline( points ) {

    console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );

    CatmullRomCurve3.call( this, points );
    this.type = 'catmullrom';

}

Spline.prototype = Object.create( CatmullRomCurve3.prototype );

Object.assign( Spline.prototype, {

    initFromArray: function ( a ) {

        console.error( 'THREE.Spline: .initFromArray() has been removed.' );

    },
    getControlPointsArray: function ( optionalTarget ) {

        console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );

    },
    reparametrizeByArcLength: function ( samplingCoef ) {

        console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );

    }

} );

//
function BoundingBoxHelper( object, color ) {

    console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
    return new BoxHelper( object, color );

}

function EdgesHelper( object, hex ) {

    console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
    return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );

}

GridHelper.prototype.setColors = function () {

    console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );

};

SkeletonHelper.prototype.update = function () {

    console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
    
};

function WireframeHelper( object, hex ) {

    console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
    return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );

}

//

function XHRLoader( manager ) {

    console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
    return new FileLoader( manager );

}

function BinaryTextureLoader( manager ) {

    console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
    return new DataTextureLoader( manager );

}

//

Object.assign( Box2.prototype, {

    center: function ( optionalTarget ) {

        console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
        return this.getCenter( optionalTarget );

    },
    empty: function () {

        console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
        return this.isEmpty();

    },
    isIntersectionBox: function ( box ) {

        console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
        return this.intersectsBox( box );

    },
    size: function ( optionalTarget ) {

        console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
        return this.getSize( optionalTarget );

    }
} );

Object.assign( Box3.prototype, {

    center: function ( optionalTarget ) {

        console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
        return this.getCenter( optionalTarget );

    },
    empty: function () {

        console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
        return this.isEmpty();

    },
    isIntersectionBox: function ( box ) {

        console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
        return this.intersectsBox( box );

    },
    isIntersectionSphere: function ( sphere ) {

        console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
        return this.intersectsSphere( sphere );

    },
    size: function ( optionalTarget ) {

        console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
        return this.getSize( optionalTarget );

    }
} );

Line3.prototype.center = function ( optionalTarget ) {

    console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
    return this.getCenter( optionalTarget );

};

_Math.random16 = function () {

    console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );
    return Math.random();

};

Object.assign( Matrix3.prototype, {

    flattenToArrayOffset: function ( array, offset ) {

        console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
        return this.toArray( array, offset );

    },
    multiplyVector3: function ( vector ) {

        console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
        return vector.applyMatrix3( this );

    },
    multiplyVector3Array: function ( a ) {

        console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.'  );

    },
    applyToBuffer: function( buffer, offset, length ) {

        console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
        return this.applyToBufferAttribute( buffer );

    },
    applyToVector3Array: function( array, offset, length ) {

        console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );

    }

} );

Object.assign( Matrix4.prototype, {

    extractPosition: function ( m ) {

        console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
        return this.copyPosition( m );

    },
    flattenToArrayOffset: function ( array, offset ) {

        console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
        return this.toArray( array, offset );

    },
    getPosition: function () {

        var v1;

        return function getPosition() {

            if ( v1 === undefined ) v1 = new Vector3();
            console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
            return v1.setFromMatrixColumn( this, 3 );

        };

    }(),
    setRotationFromQuaternion: function ( q ) {

        console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
        return this.makeRotationFromQuaternion( q );

    },
    multiplyToArray: function () {

        console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );

    },
    multiplyVector3: function ( vector ) {

        console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
        return vector.applyMatrix4( this );

    },
    multiplyVector4: function ( vector ) {

        console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
        return vector.applyMatrix4( this );

    },
    multiplyVector3Array: function ( a ) {

        console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.'  );

    },
    rotateAxis: function ( v ) {

        console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
        v.transformDirection( this );

    },
    crossVector: function ( vector ) {

        console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
        return vector.applyMatrix4( this );

    },
    translate: function () {

        console.error( 'THREE.Matrix4: .translate() has been removed.' );

    },
    rotateX: function () {

        console.error( 'THREE.Matrix4: .rotateX() has been removed.' );

    },
    rotateY: function () {

        console.error( 'THREE.Matrix4: .rotateY() has been removed.' );

    },
    rotateZ: function () {

        console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );

    },
    rotateByAxis: function () {

        console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );

    },
    applyToBuffer: function( buffer, offset, length ) {

        console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
        return this.applyToBufferAttribute( buffer );

    },
    applyToVector3Array: function( array, offset, length ) {

        console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );

    },
    makeFrustum: function( left, right, bottom, top, near, far ) {

        console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
        return this.makePerspective( left, right, top, bottom, near, far );

    }

} );

Plane.prototype.isIntersectionLine = function ( line ) {

    console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
    return this.intersectsLine( line );

};

Quaternion.prototype.multiplyVector3 = function ( vector ) {

    console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
    return vector.applyQuaternion( this );

};

Object.assign( Ray.prototype, {

    isIntersectionBox: function ( box ) {

        console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
        return this.intersectsBox( box );

    },
    isIntersectionPlane: function ( plane ) {

        console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
        return this.intersectsPlane( plane );

    },
    isIntersectionSphere: function ( sphere ) {

        console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
        return this.intersectsSphere( sphere );

    }

} );

Object.assign( Shape.prototype, {

    extrude: function ( options ) {

        console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
        return new ExtrudeGeometry( this, options );

    },
    makeGeometry: function ( options ) {

        console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
        return new ShapeGeometry( this, options );

    }

} );

Object.assign( Vector2.prototype, {

    fromAttribute: function ( attribute, index, offset ) {

        console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
        return this.fromBufferAttribute( attribute, index, offset );

    }

} );

Object.assign( Vector3.prototype, {

    setEulerFromRotationMatrix: function () {

        console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );

    },
    setEulerFromQuaternion: function () {

        console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );

    },
    getPositionFromMatrix: function ( m ) {

        console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
        return this.setFromMatrixPosition( m );

    },
    getScaleFromMatrix: function ( m ) {

        console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
        return this.setFromMatrixScale( m );

    },
    getColumnFromMatrix: function ( index, matrix ) {

        console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
        return this.setFromMatrixColumn( matrix, index );

    },
    applyProjection: function ( m ) {

        console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
        return this.applyMatrix4( m );

    },
    fromAttribute: function ( attribute, index, offset ) {

        console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
        return this.fromBufferAttribute( attribute, index, offset );

    }

} );

Object.assign( Vector4.prototype, {

    fromAttribute: function ( attribute, index, offset ) {

        console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
        return this.fromBufferAttribute( attribute, index, offset );

    }

} );

//

Geometry.prototype.computeTangents = function () {

    console.warn( 'THREE.Geometry: .computeTangents() has been removed.' );

};

Object.assign( Object3D.prototype, {

    getChildByName: function ( name ) {

        console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
        return this.getObjectByName( name );

    },
    renderDepth: function () {

        console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );

    },
    translate: function ( distance, axis ) {

        console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
        return this.translateOnAxis( axis, distance );

    }

} );

Object.defineProperties( Object3D.prototype, {

    eulerOrder: {
        get: function () {

            console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
            return this.rotation.order;

        },
        set: function ( value ) {

            console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
            this.rotation.order = value;

        }
    },
    useQuaternion: {
        get: function () {

            console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );

        },
        set: function () {

            console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );

        }
    }

} );

Object.defineProperties( LOD.prototype, {

    objects: {
        get: function () {

            console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
            return this.levels;

        }
    }

} );

Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {

    get: function () {

        console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );

    },
    set: function () {

        console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );

    }

} );

Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {

    get: function () {

        console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
        return this.arcLengthDivisions;

    },
    set: function ( value ) {

        console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
        this.arcLengthDivisions = value;

    }

} );

//

PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {

    console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
            "Use .setFocalLength and .filmGauge for a photographic setup." );

    if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
    this.setFocalLength( focalLength );

};

//

Object.defineProperties( Light.prototype, {
    onlyShadow: {
        set: function () {

            console.warn( 'THREE.Light: .onlyShadow has been removed.' );

        }
    },
    shadowCameraFov: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
            this.shadow.camera.fov = value;

        }
    },
    shadowCameraLeft: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
            this.shadow.camera.left = value;

        }
    },
    shadowCameraRight: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
            this.shadow.camera.right = value;

        }
    },
    shadowCameraTop: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
            this.shadow.camera.top = value;

        }
    },
    shadowCameraBottom: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
            this.shadow.camera.bottom = value;

        }
    },
    shadowCameraNear: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
            this.shadow.camera.near = value;

        }
    },
    shadowCameraFar: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
            this.shadow.camera.far = value;

        }
    },
    shadowCameraVisible: {
        set: function () {

            console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );

        }
    },
    shadowBias: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
            this.shadow.bias = value;

        }
    },
    shadowDarkness: {
        set: function () {

            console.warn( 'THREE.Light: .shadowDarkness has been removed.' );

        }
    },
    shadowMapWidth: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
            this.shadow.mapSize.width = value;

        }
    },
    shadowMapHeight: {
        set: function ( value ) {

            console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
            this.shadow.mapSize.height = value;

        }
    }
} );

//

Object.defineProperties( BufferAttribute.prototype, {

    length: {
        get: function () {

            console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
            return this.array.length;

        }
    }

} );

Object.assign( BufferGeometry.prototype, {

    addIndex: function ( index ) {

        console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
        this.setIndex( index );

    },
    addDrawCall: function ( start, count, indexOffset ) {

        if ( indexOffset !== undefined ) {

            console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );

        }
        console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
        this.addGroup( start, count );

    },
    clearDrawCalls: function () {

        console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
        this.clearGroups();

    },
    computeTangents: function () {

        console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );

    },
    computeOffsets: function () {

        console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );

    }

} );

Object.defineProperties( BufferGeometry.prototype, {

    drawcalls: {
        get: function () {

            console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
            return this.groups;

        }
    },
    offsets: {
        get: function () {

            console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
            return this.groups;

        }
    }

} );

//

Object.defineProperties( Uniform.prototype, {

    dynamic: {
        set: function () {

            console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );

        }
    },
    onUpdate: {
        value: function () {

            console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
            return this;

        }
    }

} );

//

Object.defineProperties( Material.prototype, {

    wrapAround: {
        get: function () {

            console.warn( 'THREE.Material: .wrapAround has been removed.' );

        },
        set: function () {

            console.warn( 'THREE.Material: .wrapAround has been removed.' );

        }
    },
    wrapRGB: {
        get: function () {

            console.warn( 'THREE.Material: .wrapRGB has been removed.' );
            return new Color();

        }
    }

} );

Object.defineProperties( MeshPhongMaterial.prototype, {

    metal: {
        get: function () {

            console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
            return false;

        },
        set: function () {

            console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );

        }
    }

} );

Object.defineProperties( ShaderMaterial.prototype, {

    derivatives: {
        get: function () {

            console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
            return this.extensions.derivatives;

        },
        set: function ( value ) {

            console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
            this.extensions.derivatives = value;

        }
    }

} );

//

Object.assign( WebGLRenderer.prototype, {

    getCurrentRenderTarget: function () {

        console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
        return this.getRenderTarget();

    },

    supportsFloatTextures: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
        return this.extensions.get( 'OES_texture_float' );

    },
    supportsHalfFloatTextures: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
        return this.extensions.get( 'OES_texture_half_float' );

    },
    supportsStandardDerivatives: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
        return this.extensions.get( 'OES_standard_derivatives' );

    },
    supportsCompressedTextureS3TC: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
        return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );

    },
    supportsCompressedTexturePVRTC: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
        return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );

    },
    supportsBlendMinMax: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
        return this.extensions.get( 'EXT_blend_minmax' );

    },
    supportsVertexTextures: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
        return this.capabilities.vertexTextures;

    },
    supportsInstancedArrays: function () {

        console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
        return this.extensions.get( 'ANGLE_instanced_arrays' );

    },
    enableScissorTest: function ( boolean ) {

        console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
        this.setScissorTest( boolean );

    },
    initMaterial: function () {

        console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );

    },
    addPrePlugin: function () {

        console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );

    },
    addPostPlugin: function () {

        console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );

    },
    updateShadowMap: function () {

        console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );

    }

} );

Object.defineProperties( WebGLRenderer.prototype, {

    shadowMapEnabled: {
        get: function () {

            return this.shadowMap.enabled;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
            this.shadowMap.enabled = value;

        }
    },
    shadowMapType: {
        get: function () {

            return this.shadowMap.type;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
            this.shadowMap.type = value;

        }
    },
    shadowMapCullFace: {
        get: function () {

            return this.shadowMap.cullFace;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' );
            this.shadowMap.cullFace = value;

        }
    }
} );

Object.defineProperties( WebGLShadowMap.prototype, {

    cullFace: {
        get: function () {

            return this.renderReverseSided ? CullFaceFront : CullFaceBack;

        },
        set: function ( cullFace ) {

            var value = ( cullFace !== CullFaceBack );
            console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." );
            this.renderReverseSided = value;

        }
    }

} );

//

Object.defineProperties( WebGLRenderTarget.prototype, {

    wrapS: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
            return this.texture.wrapS;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
            this.texture.wrapS = value;

        }
    },
    wrapT: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
            return this.texture.wrapT;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
            this.texture.wrapT = value;

        }
    },
    magFilter: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
            return this.texture.magFilter;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
            this.texture.magFilter = value;

        }
    },
    minFilter: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
            return this.texture.minFilter;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
            this.texture.minFilter = value;

        }
    },
    anisotropy: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
            return this.texture.anisotropy;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
            this.texture.anisotropy = value;

        }
    },
    offset: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
            return this.texture.offset;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
            this.texture.offset = value;

        }
    },
    repeat: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
            return this.texture.repeat;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
            this.texture.repeat = value;

        }
    },
    format: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
            return this.texture.format;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
            this.texture.format = value;

        }
    },
    type: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
            return this.texture.type;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
            this.texture.type = value;

        }
    },
    generateMipmaps: {
        get: function () {

            console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
            return this.texture.generateMipmaps;

        },
        set: function ( value ) {

            console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
            this.texture.generateMipmaps = value;

        }
    }

} );

//

Audio.prototype.load = function ( file ) {

    console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
    var scope = this;
    var audioLoader = new AudioLoader();
    audioLoader.load( file, function ( buffer ) {

        scope.setBuffer( buffer );

    } );
    return this;

};

AudioAnalyser.prototype.getData = function () {

    console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
    return this.getFrequencyData();

};

//

var GeometryUtils = {

    merge: function ( geometry1, geometry2, materialIndexOffset ) {

        console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
        var matrix;

        if ( geometry2.isMesh ) {

            geometry2.matrixAutoUpdate && geometry2.updateMatrix();

            matrix = geometry2.matrix;
            geometry2 = geometry2.geometry;

        }

        geometry1.merge( geometry2, matrix, materialIndexOffset );

    },

    center: function ( geometry ) {

        console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
        return geometry.center();

    }

};

var ImageUtils = {

    crossOrigin: undefined,

    loadTexture: function ( url, mapping, onLoad, onError ) {

        console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );

        var loader = new TextureLoader();
        loader.setCrossOrigin( this.crossOrigin );

        var texture = loader.load( url, onLoad, undefined, onError );

        if ( mapping ) texture.mapping = mapping;

        return texture;

    },

    loadTextureCube: function ( urls, mapping, onLoad, onError ) {

        console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );

        var loader = new CubeTextureLoader();
        loader.setCrossOrigin( this.crossOrigin );

        var texture = loader.load( urls, onLoad, undefined, onError );

        if ( mapping ) texture.mapping = mapping;

        return texture;

    },

    loadCompressedTexture: function () {

        console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );

    },

    loadCompressedTextureCube: function () {

        console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );

    }

};

//

function Projector() {

    console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );

    this.projectVector = function ( vector, camera ) {

        console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
        vector.project( camera );

    };

    this.unprojectVector = function ( vector, camera ) {

        console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
        vector.unproject( camera );

    };

    this.pickingRay = function () {

        console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );

    };

}

//

function CanvasRenderer() {

    console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );

    this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
    this.clear = function () {};
    this.render = function () {};
    this.setClearColor = function () {};
    this.setSize = function () {};

}




/***/ }),
/* 193 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Play button
 */
var PlayButton = function (_Button) {
  _inherits(PlayButton, _Button);

  function PlayButton() {
    _classCallCheck(this, PlayButton);

    return _possibleConstructorReturn(this, (PlayButton.__proto__ || Object.getPrototypeOf(PlayButton)).apply(this, arguments));
  }

  return PlayButton;
}(_Button3.default);

PlayButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'PlayButton',
  children: _react2.default.createElement(_icons.PlayIcon, null),
  isEnabled: false
});
exports.default = PlayButton;

/***/ }),
/* 194 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Pause button
 */
var PauseButton = function (_Button) {
  _inherits(PauseButton, _Button);

  function PauseButton() {
    _classCallCheck(this, PauseButton);

    return _possibleConstructorReturn(this, (PauseButton.__proto__ || Object.getPrototypeOf(PauseButton)).apply(this, arguments));
  }

  return PauseButton;
}(_Button3.default);

PauseButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'PauseButton',
  children: _react2.default.createElement(_icons.PauseIcon, null)
});
exports.default = PauseButton;

/***/ }),
/* 195 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Previous button
 */
var PrevButton = function (_Button) {
  _inherits(PrevButton, _Button);

  function PrevButton() {
    _classCallCheck(this, PrevButton);

    return _possibleConstructorReturn(this, (PrevButton.__proto__ || Object.getPrototypeOf(PrevButton)).apply(this, arguments));
  }

  return PrevButton;
}(_Button3.default);

PrevButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'PrevButton',
  children: _react2.default.createElement(_icons.PreviousIcon, null),
  isEnabled: false
});
exports.default = PrevButton;

/***/ }),
/* 196 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Next button
 */
var NextButton = function (_Button) {
  _inherits(NextButton, _Button);

  function NextButton() {
    _classCallCheck(this, NextButton);

    return _possibleConstructorReturn(this, (NextButton.__proto__ || Object.getPrototypeOf(NextButton)).apply(this, arguments));
  }

  return NextButton;
}(_Button3.default);

NextButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'NextButton',
  children: _react2.default.createElement(_icons.NextIcon, null),
  isEnabled: false
});
exports.default = NextButton;

/***/ }),
/* 197 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ControlDirection = 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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _composers = __webpack_require__(88);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

var oneOfType = _propTypes2.default.oneOfType,
    shape = _propTypes2.default.shape,
    func = _propTypes2.default.func,
    number = _propTypes2.default.number,
    oneOf = _propTypes2.default.oneOf,
    object = _propTypes2.default.object;

// Range control directions

var ControlDirection = exports.ControlDirection = {
  HORIZONTAL: 'HORIZONTAL',
  VERTICAL: 'VERTICAL'

  /**
   * An invisible overlay that acts as a range mouse control
   * within a specified bounds.
   */
};var RangeControlOverlay = (_class = function (_Component) {
  _inherits(RangeControlOverlay, _Component);

  function RangeControlOverlay(props) {
    _classCallCheck(this, RangeControlOverlay);

    var _this = _possibleConstructorReturn(this, (RangeControlOverlay.__proto__ || Object.getPrototypeOf(RangeControlOverlay)).call(this, props));

    _this.state = {
      isDragging: false
    };
    return _this;
  }

  _createClass(RangeControlOverlay, [{
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      this.endDrag();
    }
  }, {
    key: 'startDrag',
    value: function startDrag(evt) {
      this.setState({ isDragging: true });
      window.addEventListener('mousemove', this.triggerRangeChange);
      window.addEventListener('mouseup', this.endDrag);

      this.toggleSelection('none');

      var startValue = evt ? this.getValueFromMouseEvent(evt) : null;
      this.props.onChangeStart(startValue);
    }
  }, {
    key: 'endDrag',
    value: function endDrag(evt) {
      if (evt) {
        this.triggerRangeChange(evt);
      }

      this.setState({ isDragging: false });
      window.removeEventListener('mousemove', this.triggerRangeChange);
      window.removeEventListener('mouseup', this.endDrag);

      this.toggleSelection('');

      var endValue = evt ? this.getValueFromMouseEvent(evt) : null;
      this.props.onChangeEnd(endValue);
    }
  }, {
    key: 'toggleSelection',
    value: function toggleSelection(value) {
      var body = document.getElementsByTagName('body')[0];
      body.style['user-select'] = value;
      body.style['-webkit-user-select'] = value;
      body.style['-moz-user-select'] = value;
      body.style['-ms-user-select'] = value;
    }
  }, {
    key: 'getValueFromMouseEvent',
    value: function getValueFromMouseEvent(mouseEvent) {
      return this.props.direction === ControlDirection.VERTICAL ? this.getVerticalValue(mouseEvent.pageY) : this.getHorizontalValue(mouseEvent.pageX);
    }
  }, {
    key: 'triggerRangeChange',
    value: function triggerRangeChange(mouseEvent) {
      this.props.onValue(this.getValueFromMouseEvent(mouseEvent));
    }
  }, {
    key: 'handleIntentMove',
    value: function handleIntentMove(evt) {
      if (!this.state.isDragging) {
        this.triggerIntent(evt);
      }
    }
  }, {
    key: 'triggerIntent',
    value: function triggerIntent(mouseEvent) {
      var _props = this.props,
          direction = _props.direction,
          onIntent = _props.onIntent;


      var value = direction === ControlDirection.VERTICAL ? this.getVerticalValue(mouseEvent.pageY) : this.getHorizontalValue(mouseEvent.pageX);

      onIntent(value);
    }
  }, {
    key: 'getRectFromBounds',
    value: function getRectFromBounds() {
      var bounds = this.props.bounds;


      return typeof bounds === 'function' ? bounds() : bounds;
    }
  }, {
    key: 'getHorizontalValue',
    value: function getHorizontalValue(mouseX) {
      var rect = this.getRectFromBounds();
      var scrollX = window.pageXOffset !== undefined ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
      var dLeft = mouseX - (rect.left + scrollX);
      dLeft = Math.max(dLeft, 0);
      dLeft = Math.min(dLeft, rect.width);

      return dLeft / rect.width;
    }
  }, {
    key: 'getVerticalValue',
    value: function getVerticalValue(mouseY) {
      var rect = this.getRectFromBounds();
      var scrollY = window.pageYOffset !== undefined ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
      var dTop = mouseY - (rect.top + scrollY);
      dTop = Math.max(dTop, 0);
      dTop = Math.min(dTop, rect.height);

      return 1 - dTop / rect.height;
    }
  }, {
    key: 'render',
    value: function render() {
      var _props2 = this.props,
          className = _props2.className,
          extraClasses = _props2.extraClasses,
          style = _props2.style;
      var isDragging = this.state.isDragging;


      return _react2.default.createElement('div', {
        className: (0, _classnames2.default)(className, extraClasses, { isDragging: isDragging }),
        style: style,
        onMouseDown: this.startDrag,
        onMouseMove: this.handleIntentMove
      });
    }
  }]);

  return RangeControlOverlay;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'startDrag', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'startDrag'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'endDrag', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'endDrag'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'triggerRangeChange', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'triggerRangeChange'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleIntentMove', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleIntentMove'), _class.prototype)), _class);
RangeControlOverlay.propTypes = {
  bounds: oneOfType([func, shape({
    width: number.isRequired,
    left: number.isRequired
  }), shape({
    height: number.isRequired,
    top: number.isRequired
  })]).isRequired,
  onValue: func.isRequired,
  onChangeStart: func,
  onChangeEnd: func,
  onIntent: func,
  direction: oneOf([ControlDirection.HORIZONTAL, ControlDirection.VERTICAL]),
  style: object
};
RangeControlOverlay.defaultProps = {
  onChangeStart: function onChangeStart() {},
  onChangeEnd: function onChangeEnd() {},
  onIntent: function onIntent() {},
  direction: ControlDirection.HORIZONTAL,
  style: {}
};
exports.default = (0, _composers.withCustomizableClasses)('RangeControlOverlay')(RangeControlOverlay);

/***/ }),
/* 198 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _composers = __webpack_require__(88);

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 number = _propTypes2.default.number,
    object = _propTypes2.default.object;


var padZero = function padZero(digit) {
  return '' + (digit < 10 ? '0' : '') + digit;
};

/**
 * Time formatter that turns seconds into h:mm:ss
 */

var FormattedTime = function (_Component) {
  _inherits(FormattedTime, _Component);

  function FormattedTime() {
    _classCallCheck(this, FormattedTime);

    return _possibleConstructorReturn(this, (FormattedTime.__proto__ || Object.getPrototypeOf(FormattedTime)).apply(this, arguments));
  }

  _createClass(FormattedTime, [{
    key: 'getFormattedTime',
    value: function getFormattedTime() {
      var numSeconds = this.props.numSeconds;


      var prefix = numSeconds < 0 ? '-' : '';
      var absNumSeconds = Math.abs(numSeconds);

      var hours = Math.floor(absNumSeconds / 3600);
      var minutes = Math.floor(absNumSeconds % 3600 / 60);
      var seconds = Math.floor(absNumSeconds) % 60;

      return hours > 0 ? '' + prefix + hours + ':' + padZero(minutes) + ':' + padZero(seconds) : '' + prefix + minutes + ':' + padZero(seconds);
    }
  }, {
    key: 'render',
    value: function render() {
      var _props = this.props,
          style = _props.style,
          className = _props.className,
          extraClasses = _props.extraClasses;


      return _react2.default.createElement(
        'span',
        { className: (0, _classnames2.default)(className, extraClasses), style: style },
        this.getFormattedTime()
      );
    }
  }]);

  return FormattedTime;
}(_react.Component);

FormattedTime.propTypes = {
  numSeconds: number,
  style: object
};
FormattedTime.defaultProps = {
  numSeconds: 0,
  style: {}
};
exports.default = (0, _composers.withCustomizableClasses)('FormattedTime', FormattedTime);

/***/ }),
/* 199 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Sound on button
 */
var SoundOnButton = function (_Button) {
  _inherits(SoundOnButton, _Button);

  function SoundOnButton() {
    _classCallCheck(this, SoundOnButton);

    return _possibleConstructorReturn(this, (SoundOnButton.__proto__ || Object.getPrototypeOf(SoundOnButton)).apply(this, arguments));
  }

  return SoundOnButton;
}(_Button3.default);

SoundOnButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'SoundOnButton',
  children: _react2.default.createElement(_icons.SoundOnIcon, null)
});
exports.default = SoundOnButton;

/***/ }),
/* 200 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _Button2 = __webpack_require__(87);

var _Button3 = _interopRequireDefault(_Button2);

var _icons = __webpack_require__(86);

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; }

/**
 * Sound off button
 */
var SoundOffButton = function (_Button) {
  _inherits(SoundOffButton, _Button);

  function SoundOffButton() {
    _classCallCheck(this, SoundOffButton);

    return _possibleConstructorReturn(this, (SoundOffButton.__proto__ || Object.getPrototypeOf(SoundOffButton)).apply(this, arguments));
  }

  return SoundOffButton;
}(_Button3.default);

SoundOffButton.defaultProps = _extends({}, _Button3.default.defaultProps, {
  className: 'SoundOffButton',
  children: _react2.default.createElement(_icons.SoundOffIcon, null)
});
exports.default = SoundOffButton;

/***/ }),
/* 201 */
/***/ (function(module, exports, __webpack_require__) {

!function(r,c){ true?module.exports=c(__webpack_require__(11)):"function"==typeof define&&define.amd?define(["react"],c):"object"==typeof exports?exports["react-simple-flex-grid"]=c(require("react")):r["react-simple-flex-grid"]=c(r.React)}(this,function(r){return function(r){function c(t){if(o[t])return o[t].exports;var d=o[t]={i:t,l:!1,exports:{}};return r[t].call(d.exports,d,d.exports,c),d.l=!0,d.exports}var o={};return c.m=r,c.c=o,c.i=function(r){return r},c.d=function(r,o,t){c.o(r,o)||Object.defineProperty(r,o,{configurable:!1,enumerable:!0,get:t})},c.n=function(r){var o=r&&r.__esModule?function(){return r.default}:function(){return r};return c.d(o,"a",o),o},c.o=function(r,c){return Object.prototype.hasOwnProperty.call(r,c)},c.p="",c(c.s=11)}([function(r,c,o){"use strict";function t(r){return r&&r.__esModule?r:{default:r}}Object.defineProperty(c,"__esModule",{value:!0}),c.Row=c.Col=void 0;var d=o(5),l=t(d),e=o(6),i=t(e);c.Col=l.default,c.Row=i.default},function(r,c,o){var t,d;!function(){"use strict";function o(){for(var r=[],c=0;c<arguments.length;c++){var t=arguments[c];if(t){var d=typeof t;if("string"===d||"number"===d)r.push(t);else if(Array.isArray(t))r.push(o.apply(null,t));else if("object"===d)for(var e in t)l.call(t,e)&&t[e]&&r.push(e)}}return r.join(" ")}var l={}.hasOwnProperty;void 0!==r&&r.exports?r.exports=o:(t=[],void 0!==(d=function(){return o}.apply(c,t))&&(r.exports=d))}()},function(r,c){r.exports={"rct-grid-row":"rct-grid-row","rct-grid-row-start":"rct-grid-row-start","rct-grid-row-center":"rct-grid-row-center","rct-grid-row-end":"rct-grid-row-end","rct-grid-row-space-between":"rct-grid-row-space-between","rct-grid-row-space-around":"rct-grid-row-space-around","rct-grid-row-top":"rct-grid-row-top","rct-grid-row-middle":"rct-grid-row-middle","rct-grid-row-bottom":"rct-grid-row-bottom","rct-grid-col-1":"rct-grid-col-1","rct-grid-col-xs-1":"rct-grid-col-xs-1","rct-grid-col-sm-1":"rct-grid-col-sm-1","rct-grid-col-md-1":"rct-grid-col-md-1","rct-grid-col-lg-1":"rct-grid-col-lg-1","rct-grid-col-2":"rct-grid-col-2","rct-grid-col-xs-2":"rct-grid-col-xs-2","rct-grid-col-sm-2":"rct-grid-col-sm-2","rct-grid-col-md-2":"rct-grid-col-md-2","rct-grid-col-lg-2":"rct-grid-col-lg-2","rct-grid-col-3":"rct-grid-col-3","rct-grid-col-xs-3":"rct-grid-col-xs-3","rct-grid-col-sm-3":"rct-grid-col-sm-3","rct-grid-col-md-3":"rct-grid-col-md-3","rct-grid-col-lg-3":"rct-grid-col-lg-3","rct-grid-col-4":"rct-grid-col-4","rct-grid-col-xs-4":"rct-grid-col-xs-4","rct-grid-col-sm-4":"rct-grid-col-sm-4","rct-grid-col-md-4":"rct-grid-col-md-4","rct-grid-col-lg-4":"rct-grid-col-lg-4","rct-grid-col-5":"rct-grid-col-5","rct-grid-col-xs-5":"rct-grid-col-xs-5","rct-grid-col-sm-5":"rct-grid-col-sm-5","rct-grid-col-md-5":"rct-grid-col-md-5","rct-grid-col-lg-5":"rct-grid-col-lg-5","rct-grid-col-6":"rct-grid-col-6","rct-grid-col-xs-6":"rct-grid-col-xs-6","rct-grid-col-sm-6":"rct-grid-col-sm-6","rct-grid-col-md-6":"rct-grid-col-md-6","rct-grid-col-lg-6":"rct-grid-col-lg-6","rct-grid-col-7":"rct-grid-col-7","rct-grid-col-xs-7":"rct-grid-col-xs-7","rct-grid-col-sm-7":"rct-grid-col-sm-7","rct-grid-col-md-7":"rct-grid-col-md-7","rct-grid-col-lg-7":"rct-grid-col-lg-7","rct-grid-col-8":"rct-grid-col-8","rct-grid-col-xs-8":"rct-grid-col-xs-8","rct-grid-col-sm-8":"rct-grid-col-sm-8","rct-grid-col-md-8":"rct-grid-col-md-8","rct-grid-col-lg-8":"rct-grid-col-lg-8","rct-grid-col-9":"rct-grid-col-9","rct-grid-col-xs-9":"rct-grid-col-xs-9","rct-grid-col-sm-9":"rct-grid-col-sm-9","rct-grid-col-md-9":"rct-grid-col-md-9","rct-grid-col-lg-9":"rct-grid-col-lg-9","rct-grid-col-10":"rct-grid-col-10","rct-grid-col-xs-10":"rct-grid-col-xs-10","rct-grid-col-sm-10":"rct-grid-col-sm-10","rct-grid-col-md-10":"rct-grid-col-md-10","rct-grid-col-lg-10":"rct-grid-col-lg-10","rct-grid-col-11":"rct-grid-col-11","rct-grid-col-xs-11":"rct-grid-col-xs-11","rct-grid-col-sm-11":"rct-grid-col-sm-11","rct-grid-col-md-11":"rct-grid-col-md-11","rct-grid-col-lg-11":"rct-grid-col-lg-11","rct-grid-col-12":"rct-grid-col-12","rct-grid-col-xs-12":"rct-grid-col-xs-12","rct-grid-col-sm-12":"rct-grid-col-sm-12","rct-grid-col-md-12":"rct-grid-col-md-12","rct-grid-col-lg-12":"rct-grid-col-lg-12","rct-grid-col-offset-1":"rct-grid-col-offset-1","rct-grid-col-order-1":"rct-grid-col-order-1","rct-grid-col-offset-2":"rct-grid-col-offset-2","rct-grid-col-order-2":"rct-grid-col-order-2","rct-grid-col-offset-3":"rct-grid-col-offset-3","rct-grid-col-order-3":"rct-grid-col-order-3","rct-grid-col-offset-4":"rct-grid-col-offset-4","rct-grid-col-order-4":"rct-grid-col-order-4","rct-grid-col-offset-5":"rct-grid-col-offset-5","rct-grid-col-order-5":"rct-grid-col-order-5","rct-grid-col-offset-6":"rct-grid-col-offset-6","rct-grid-col-order-6":"rct-grid-col-order-6","rct-grid-col-offset-7":"rct-grid-col-offset-7","rct-grid-col-order-7":"rct-grid-col-order-7","rct-grid-col-offset-8":"rct-grid-col-offset-8","rct-grid-col-order-8":"rct-grid-col-order-8","rct-grid-col-offset-9":"rct-grid-col-offset-9","rct-grid-col-order-9":"rct-grid-col-order-9","rct-grid-col-offset-10":"rct-grid-col-offset-10","rct-grid-col-order-10":"rct-grid-col-order-10","rct-grid-col-offset-11":"rct-grid-col-offset-11","rct-grid-col-order-11":"rct-grid-col-order-11","rct-grid-col-offset-12":"rct-grid-col-offset-12","rct-grid-col-order-12":"rct-grid-col-order-12","rct-grid-col-xs-offset-1":"rct-grid-col-xs-offset-1","rct-grid-col-xs-order-1":"rct-grid-col-xs-order-1","rct-grid-col-xs-offset-2":"rct-grid-col-xs-offset-2","rct-grid-col-xs-order-2":"rct-grid-col-xs-order-2","rct-grid-col-xs-offset-3":"rct-grid-col-xs-offset-3","rct-grid-col-xs-order-3":"rct-grid-col-xs-order-3","rct-grid-col-xs-offset-4":"rct-grid-col-xs-offset-4","rct-grid-col-xs-order-4":"rct-grid-col-xs-order-4","rct-grid-col-xs-offset-5":"rct-grid-col-xs-offset-5","rct-grid-col-xs-order-5":"rct-grid-col-xs-order-5","rct-grid-col-xs-offset-6":"rct-grid-col-xs-offset-6","rct-grid-col-xs-order-6":"rct-grid-col-xs-order-6","rct-grid-col-xs-offset-7":"rct-grid-col-xs-offset-7","rct-grid-col-xs-order-7":"rct-grid-col-xs-order-7","rct-grid-col-xs-offset-8":"rct-grid-col-xs-offset-8","rct-grid-col-xs-order-8":"rct-grid-col-xs-order-8","rct-grid-col-xs-offset-9":"rct-grid-col-xs-offset-9","rct-grid-col-xs-order-9":"rct-grid-col-xs-order-9","rct-grid-col-xs-offset-10":"rct-grid-col-xs-offset-10","rct-grid-col-xs-order-10":"rct-grid-col-xs-order-10","rct-grid-col-xs-offset-11":"rct-grid-col-xs-offset-11","rct-grid-col-xs-order-11":"rct-grid-col-xs-order-11","rct-grid-col-xs-offset-12":"rct-grid-col-xs-offset-12","rct-grid-col-xs-order-12":"rct-grid-col-xs-order-12","rct-grid-col-sm-offset-1":"rct-grid-col-sm-offset-1","rct-grid-col-sm-order-1":"rct-grid-col-sm-order-1","rct-grid-col-sm-offset-2":"rct-grid-col-sm-offset-2","rct-grid-col-sm-order-2":"rct-grid-col-sm-order-2","rct-grid-col-sm-offset-3":"rct-grid-col-sm-offset-3","rct-grid-col-sm-order-3":"rct-grid-col-sm-order-3","rct-grid-col-sm-offset-4":"rct-grid-col-sm-offset-4","rct-grid-col-sm-order-4":"rct-grid-col-sm-order-4","rct-grid-col-sm-offset-5":"rct-grid-col-sm-offset-5","rct-grid-col-sm-order-5":"rct-grid-col-sm-order-5","rct-grid-col-sm-offset-6":"rct-grid-col-sm-offset-6","rct-grid-col-sm-order-6":"rct-grid-col-sm-order-6","rct-grid-col-sm-offset-7":"rct-grid-col-sm-offset-7","rct-grid-col-sm-order-7":"rct-grid-col-sm-order-7","rct-grid-col-sm-offset-8":"rct-grid-col-sm-offset-8","rct-grid-col-sm-order-8":"rct-grid-col-sm-order-8","rct-grid-col-sm-offset-9":"rct-grid-col-sm-offset-9","rct-grid-col-sm-order-9":"rct-grid-col-sm-order-9","rct-grid-col-sm-offset-10":"rct-grid-col-sm-offset-10","rct-grid-col-sm-order-10":"rct-grid-col-sm-order-10","rct-grid-col-sm-offset-11":"rct-grid-col-sm-offset-11","rct-grid-col-sm-order-11":"rct-grid-col-sm-order-11","rct-grid-col-sm-offset-12":"rct-grid-col-sm-offset-12","rct-grid-col-sm-order-12":"rct-grid-col-sm-order-12","rct-grid-col-md-offset-1":"rct-grid-col-md-offset-1","rct-grid-col-md-order-1":"rct-grid-col-md-order-1","rct-grid-col-md-offset-2":"rct-grid-col-md-offset-2","rct-grid-col-md-order-2":"rct-grid-col-md-order-2","rct-grid-col-md-offset-3":"rct-grid-col-md-offset-3","rct-grid-col-md-order-3":"rct-grid-col-md-order-3","rct-grid-col-md-offset-4":"rct-grid-col-md-offset-4","rct-grid-col-md-order-4":"rct-grid-col-md-order-4","rct-grid-col-md-offset-5":"rct-grid-col-md-offset-5","rct-grid-col-md-order-5":"rct-grid-col-md-order-5","rct-grid-col-md-offset-6":"rct-grid-col-md-offset-6","rct-grid-col-md-order-6":"rct-grid-col-md-order-6","rct-grid-col-md-offset-7":"rct-grid-col-md-offset-7","rct-grid-col-md-order-7":"rct-grid-col-md-order-7","rct-grid-col-md-offset-8":"rct-grid-col-md-offset-8","rct-grid-col-md-order-8":"rct-grid-col-md-order-8","rct-grid-col-md-offset-9":"rct-grid-col-md-offset-9","rct-grid-col-md-order-9":"rct-grid-col-md-order-9","rct-grid-col-md-offset-10":"rct-grid-col-md-offset-10","rct-grid-col-md-order-10":"rct-grid-col-md-order-10","rct-grid-col-md-offset-11":"rct-grid-col-md-offset-11","rct-grid-col-md-order-11":"rct-grid-col-md-order-11","rct-grid-col-md-offset-12":"rct-grid-col-md-offset-12","rct-grid-col-md-order-12":"rct-grid-col-md-order-12","rct-grid-col-lg-offset-1":"rct-grid-col-lg-offset-1","rct-grid-col-lg-order-1":"rct-grid-col-lg-order-1","rct-grid-col-lg-offset-2":"rct-grid-col-lg-offset-2","rct-grid-col-lg-order-2":"rct-grid-col-lg-order-2","rct-grid-col-lg-offset-3":"rct-grid-col-lg-offset-3","rct-grid-col-lg-order-3":"rct-grid-col-lg-order-3","rct-grid-col-lg-offset-4":"rct-grid-col-lg-offset-4","rct-grid-col-lg-order-4":"rct-grid-col-lg-order-4","rct-grid-col-lg-offset-5":"rct-grid-col-lg-offset-5","rct-grid-col-lg-order-5":"rct-grid-col-lg-order-5","rct-grid-col-lg-offset-6":"rct-grid-col-lg-offset-6","rct-grid-col-lg-order-6":"rct-grid-col-lg-order-6","rct-grid-col-lg-offset-7":"rct-grid-col-lg-offset-7","rct-grid-col-lg-order-7":"rct-grid-col-lg-order-7","rct-grid-col-lg-offset-8":"rct-grid-col-lg-offset-8","rct-grid-col-lg-order-8":"rct-grid-col-lg-order-8","rct-grid-col-lg-offset-9":"rct-grid-col-lg-offset-9","rct-grid-col-lg-order-9":"rct-grid-col-lg-order-9","rct-grid-col-lg-offset-10":"rct-grid-col-lg-offset-10","rct-grid-col-lg-order-10":"rct-grid-col-lg-order-10","rct-grid-col-lg-offset-11":"rct-grid-col-lg-offset-11","rct-grid-col-lg-order-11":"rct-grid-col-lg-order-11","rct-grid-col-lg-offset-12":"rct-grid-col-lg-offset-12","rct-grid-col-lg-order-12":"rct-grid-col-lg-order-12","rct-grid-col-xl-1":"rct-grid-col-xl-1","rct-grid-col-xl-2":"rct-grid-col-xl-2","rct-grid-col-xl-3":"rct-grid-col-xl-3","rct-grid-col-xl-4":"rct-grid-col-xl-4","rct-grid-col-xl-5":"rct-grid-col-xl-5","rct-grid-col-xl-6":"rct-grid-col-xl-6","rct-grid-col-xl-7":"rct-grid-col-xl-7","rct-grid-col-xl-8":"rct-grid-col-xl-8","rct-grid-col-xl-9":"rct-grid-col-xl-9","rct-grid-col-xl-10":"rct-grid-col-xl-10","rct-grid-col-xl-11":"rct-grid-col-xl-11","rct-grid-col-xl-12":"rct-grid-col-xl-12","rct-grid-col-xl-offset-1":"rct-grid-col-xl-offset-1","rct-grid-col-xl-order-1":"rct-grid-col-xl-order-1","rct-grid-col-xl-offset-2":"rct-grid-col-xl-offset-2","rct-grid-col-xl-order-2":"rct-grid-col-xl-order-2","rct-grid-col-xl-offset-3":"rct-grid-col-xl-offset-3","rct-grid-col-xl-order-3":"rct-grid-col-xl-order-3","rct-grid-col-xl-offset-4":"rct-grid-col-xl-offset-4","rct-grid-col-xl-order-4":"rct-grid-col-xl-order-4","rct-grid-col-xl-offset-5":"rct-grid-col-xl-offset-5","rct-grid-col-xl-order-5":"rct-grid-col-xl-order-5","rct-grid-col-xl-offset-6":"rct-grid-col-xl-offset-6","rct-grid-col-xl-order-6":"rct-grid-col-xl-order-6","rct-grid-col-xl-offset-7":"rct-grid-col-xl-offset-7","rct-grid-col-xl-order-7":"rct-grid-col-xl-order-7","rct-grid-col-xl-offset-8":"rct-grid-col-xl-offset-8","rct-grid-col-xl-order-8":"rct-grid-col-xl-order-8","rct-grid-col-xl-offset-9":"rct-grid-col-xl-offset-9","rct-grid-col-xl-order-9":"rct-grid-col-xl-order-9","rct-grid-col-xl-offset-10":"rct-grid-col-xl-offset-10","rct-grid-col-xl-order-10":"rct-grid-col-xl-order-10","rct-grid-col-xl-offset-11":"rct-grid-col-xl-offset-11","rct-grid-col-xl-order-11":"rct-grid-col-xl-order-11","rct-grid-col-xl-offset-12":"rct-grid-col-xl-offset-12","rct-grid-col-xl-order-12":"rct-grid-col-xl-order-12"}},function(r,c,o){r.exports=o(7)()},function(c,o){c.exports=r},function(r,c,o){"use strict";function t(r){return r&&r.__esModule?r:{default:r}}function d(r,c,o){return c in r?Object.defineProperty(r,c,{value:o,enumerable:!0,configurable:!0,writable:!0}):r[c]=o,r}function l(r,c){var o={};for(var t in r)c.indexOf(t)>=0||Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o}function e(r){var c,o=r.span,t=r.offset,e=r.className,f=r.children,n=r.prefix,u=void 0===n?"rct-grid-col":n,a=r.order,x=l(r,["span","offset","className","children","prefix","order"]),y={};["xs","sm","md","lg","xl"].forEach(function(r){if(x[r]){var c,o={};"number"==typeof x[r]?o.span=x[r]:"object"===g(x[r])&&(o=x[r]||{}),delete x[r],y=Object.assign({},y,(c={},d(c,p.default[u+"-"+r+"-"+o.span],o.span),d(c,p.default[u+"-"+r+"-offset-"+o.offset],o.offset||0===o.offset),d(c,p.default[u+"-"+r+"-order-"+o.order],o.order||0===o.order),c))}});var b=(0,m.default)((c={},d(c,p.default[u+"-"+o],void 0!==o),d(c,p.default[u+"-offset-"+t],t),d(c,p.default[u+"-order-"+a],a),c),e,y);return s.default.createElement("div",i({},x,{className:b}),f)}Object.defineProperty(c,"__esModule",{value:!0});var i=Object.assign||function(r){for(var c=1;c<arguments.length;c++){var o=arguments[c];for(var t in o)Object.prototype.hasOwnProperty.call(o,t)&&(r[t]=o[t])}return r},g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(r){return typeof r}:function(r){return r&&"function"==typeof Symbol&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},f=o(4),s=t(f),n=o(3),u=t(n),a=o(1),m=t(a),x=o(2),p=t(x);u.default.oneOfType([u.default.string,u.default.number]),u.default.oneOfType([u.default.number,u.default.object]);e.defaultProps={offset:0},c.default=e},function(r,c,o){"use strict";function t(r){return r&&r.__esModule?r:{default:r}}function d(r,c,o){return c in r?Object.defineProperty(r,c,{value:o,enumerable:!0,configurable:!0,writable:!0}):r[c]=o,r}function l(r,c){var o={};for(var t in r)c.indexOf(t)>=0||Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o}function e(r,c){if(!(r instanceof c))throw new TypeError("Cannot call a class as a function")}function i(r,c){if(!r)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!c||"object"!=typeof c&&"function"!=typeof c?r:c}function g(r,c){if("function"!=typeof c&&null!==c)throw new TypeError("Super expression must either be null or a function, not "+typeof c);r.prototype=Object.create(c&&c.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),c&&(Object.setPrototypeOf?Object.setPrototypeOf(r,c):r.__proto__=c)}Object.defineProperty(c,"__esModule",{value:!0});var f=Object.assign||function(r){for(var c=1;c<arguments.length;c++){var o=arguments[c];for(var t in o)Object.prototype.hasOwnProperty.call(o,t)&&(r[t]=o[t])}return r},s=function(){function r(r,c){for(var o=0;o<c.length;o++){var t=c[o];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(r,t.key,t)}}return function(c,o,t){return o&&r(c.prototype,o),t&&r(c,t),c}}(),n=o(4),u=t(n),a=o(3),m=(t(a),o(1)),x=t(m),p=o(2),y=t(p),b=function(r){function c(){return e(this,c),i(this,(c.__proto__||Object.getPrototypeOf(c)).apply(this,arguments))}return g(c,r),s(c,[{key:"render",value:function(){var r,c=this.props,o=c.justify,t=c.align,e=c.className,i=c.gutter,g=c.style,s=c.children,n=c.prefix,a=void 0===n?"rct-grid-row":n,m=l(c,["justify","align","className","gutter","style","children","prefix"]),p=(0,x.default)(y.default[""+a],(r={},d(r,y.default[a+"-"+o],o),d(r,y.default[a+"-"+t],t),r),e),b=i>0?Object.assign({},{marginLeft:i/-2,marginRight:i/-2},g):g,v=u.default.Children.map(s,function(r){return r?r.props&&i>0?u.default.cloneElement(r,{style:Object.assign({},{paddingLeft:i/2,paddingRight:i/2},r.props.style)}):r:null});return u.default.createElement("div",f({},m,{className:p,style:b}),v)}}]),c}(u.default.Component);b.defaultProps={gutter:0,justify:"start",align:"top"},c.default=b},function(r,c,o){"use strict";var t=o(9),d=o(10),l=o(8);r.exports=function(){function r(r,c,o,t,e,i){i!==l&&d(!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")}function c(){return r}r.isRequired=r;var o={array:r,bool:r,func:r,number:r,object:r,string:r,symbol:r,any:r,arrayOf:c,element:r,instanceOf:c,node:r,objectOf:c,oneOf:c,oneOfType:c,shape:c,exact:c};return o.checkPropTypes=t,o.PropTypes=o,o}},function(r,c,o){"use strict";r.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(r,c,o){"use strict";function t(r){return function(){return r}}var d=function(){};d.thatReturns=t,d.thatReturnsFalse=t(!1),d.thatReturnsTrue=t(!0),d.thatReturnsNull=t(null),d.thatReturnsThis=function(){return this},d.thatReturnsArgument=function(r){return r},r.exports=d},function(r,c,o){"use strict";function t(r,c,o,t,l,e,i,g){if(d(c),!r){var f;if(void 0===c)f=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[o,t,l,e,i,g],n=0;f=new Error(c.replace(/%s/g,function(){return s[n++]})),f.name="Invariant Violation"}throw f.framesToPop=1,f}}var d=function(r){};r.exports=t},function(r,c,o){o(0),r.exports=o(0)}])});

/***/ }),
/* 202 */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ }),
/* 203 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


module.exports = function bind(fn, thisArg) {
  return function wrap() {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; i++) {
      args[i] = arguments[i];
    }
    return fn.apply(thisArg, args);
  };
};


/***/ }),
/* 204 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);
var settle = __webpack_require__(268);
var buildURL = __webpack_require__(270);
var parseHeaders = __webpack_require__(271);
var isURLSameOrigin = __webpack_require__(272);
var createError = __webpack_require__(205);
var btoa = (typeof window !== 'undefined' && window.btoa && window.btoa.bind(window)) || __webpack_require__(273);

module.exports = function xhrAdapter(config) {
  return new Promise(function dispatchXhrRequest(resolve, reject) {
    var requestData = config.data;
    var requestHeaders = config.headers;

    if (utils.isFormData(requestData)) {
      delete requestHeaders['Content-Type']; // Let the browser set it
    }

    var request = new XMLHttpRequest();
    var loadEvent = 'onreadystatechange';
    var xDomain = false;

    // For IE 8/9 CORS support
    // Only supports POST and GET calls and doesn't returns the response headers.
    // DON'T do this for testing b/c XMLHttpRequest is mocked, not XDomainRequest.
    if (false) {
      request = new window.XDomainRequest();
      loadEvent = 'onload';
      xDomain = true;
      request.onprogress = function handleProgress() {};
      request.ontimeout = function handleTimeout() {};
    }

    // HTTP basic authentication
    if (config.auth) {
      var username = config.auth.username || '';
      var password = config.auth.password || '';
      requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
    }

    request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);

    // Set the request timeout in MS
    request.timeout = config.timeout;

    // Listen for ready state
    request[loadEvent] = function handleLoad() {
      if (!request || (request.readyState !== 4 && !xDomain)) {
        return;
      }

      // The request errored out and we didn't get a response, this will be
      // handled by onerror instead
      // With one exception: request that using file: protocol, most browsers
      // will return status as 0 even though it's a successful request
      if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
        return;
      }

      // Prepare the response
      var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
      var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
      var response = {
        data: responseData,
        // IE sends 1223 instead of 204 (https://github.com/axios/axios/issues/201)
        status: request.status === 1223 ? 204 : request.status,
        statusText: request.status === 1223 ? 'No Content' : request.statusText,
        headers: responseHeaders,
        config: config,
        request: request
      };

      settle(resolve, reject, response);

      // Clean up request
      request = null;
    };

    // Handle low level network errors
    request.onerror = function handleError() {
      // Real errors are hidden from us by the browser
      // onerror should only fire if it's a network error
      reject(createError('Network Error', config, null, request));

      // Clean up request
      request = null;
    };

    // Handle timeout
    request.ontimeout = function handleTimeout() {
      reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED',
        request));

      // Clean up request
      request = null;
    };

    // Add xsrf header
    // This is only done if running in a standard browser environment.
    // Specifically not if we're in a web worker, or react-native.
    if (utils.isStandardBrowserEnv()) {
      var cookies = __webpack_require__(274);

      // Add xsrf header
      var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ?
          cookies.read(config.xsrfCookieName) :
          undefined;

      if (xsrfValue) {
        requestHeaders[config.xsrfHeaderName] = xsrfValue;
      }
    }

    // Add headers to the request
    if ('setRequestHeader' in request) {
      utils.forEach(requestHeaders, function setRequestHeader(val, key) {
        if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
          // Remove Content-Type if data is undefined
          delete requestHeaders[key];
        } else {
          // Otherwise add header to the request
          request.setRequestHeader(key, val);
        }
      });
    }

    // Add withCredentials to request if needed
    if (config.withCredentials) {
      request.withCredentials = true;
    }

    // Add responseType to request if needed
    if (config.responseType) {
      try {
        request.responseType = config.responseType;
      } catch (e) {
        // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
        // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
        if (config.responseType !== 'json') {
          throw e;
        }
      }
    }

    // Handle progress if needed
    if (typeof config.onDownloadProgress === 'function') {
      request.addEventListener('progress', config.onDownloadProgress);
    }

    // Not all browsers support upload events
    if (typeof config.onUploadProgress === 'function' && request.upload) {
      request.upload.addEventListener('progress', config.onUploadProgress);
    }

    if (config.cancelToken) {
      // Handle cancellation
      config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
          return;
        }

        request.abort();
        reject(cancel);
        // Clean up request
        request = null;
      });
    }

    if (requestData === undefined) {
      requestData = null;
    }

    // Send the request
    request.send(requestData);
  });
};


/***/ }),
/* 205 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var enhanceError = __webpack_require__(269);

/**
 * Create an Error with the specified message, config, error code, request and response.
 *
 * @param {string} message The error message.
 * @param {Object} config The config.
 * @param {string} [code] The error code (for example, 'ECONNABORTED').
 * @param {Object} [request] The request.
 * @param {Object} [response] The response.
 * @returns {Error} The created error.
 */
module.exports = function createError(message, config, code, request, response) {
  var error = new Error(message);
  return enhanceError(error, config, code, request, response);
};


/***/ }),
/* 206 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


module.exports = function isCancel(value) {
  return !!(value && value.__CANCEL__);
};


/***/ }),
/* 207 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * A `Cancel` is an object that is thrown when an operation is canceled.
 *
 * @class
 * @param {string=} message The message.
 */
function Cancel(message) {
  this.message = message;
}

Cancel.prototype.toString = function toString() {
  return 'Cancel' + (this.message ? ': ' + this.message : '');
};

Cancel.prototype.__CANCEL__ = true;

module.exports = Cancel;


/***/ }),
/* 208 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _styles = __webpack_require__(284);

var _styles2 = _interopRequireDefault(_styles);

var _assign = __webpack_require__(285);

var _assign2 = _interopRequireDefault(_assign);

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 SkyLightStateless = function (_React$Component) {
  _inherits(SkyLightStateless, _React$Component);

  function SkyLightStateless() {
    _classCallCheck(this, SkyLightStateless);

    return _possibleConstructorReturn(this, (SkyLightStateless.__proto__ || Object.getPrototypeOf(SkyLightStateless)).apply(this, arguments));
  }

  _createClass(SkyLightStateless, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      document.addEventListener("keydown", this._handlerEsc.bind(this));
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      document.removeEventListener("keydown", this._handlerEsc.bind(this));
    }
  }, {
    key: '_handlerEsc',
    value: function _handlerEsc(evt) {
      var isEscape = false;
      if ("key" in evt) {
        isEscape = evt.key == "Escape" || evt.key == "Esc";
      } else {
        isEscape = evt.keyCode == 27;
      }
      if (isEscape && this.props.closeOnEsc && this.props.isVisible) {
        this.props.onCloseClicked();
      }
    }
  }, {
    key: 'onOverlayClicked',
    value: function onOverlayClicked() {
      if (this.props.onOverlayClicked) {
        this.props.onOverlayClicked();
      }
    }
  }, {
    key: 'onCloseClicked',
    value: function onCloseClicked() {
      if (this.props.onCloseClicked) {
        this.props.onCloseClicked();
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      var mergeStyles = function mergeStyles(key) {
        return (0, _assign2.default)({}, _styles2.default[key], _this2.props[key]);
      };
      var isVisible = this.props.isVisible;

      var dialogStyles = mergeStyles('dialogStyles');
      var overlayStyles = mergeStyles('overlayStyles');
      var closeButtonStyle = mergeStyles('closeButtonStyle');
      var titleStyle = mergeStyles('titleStyle');

      var finalStyle = void 0;
      if (isVisible) {
        finalStyle = (0, _assign2.default)({}, dialogStyles, _styles2.default.animationOpen);
        overlayStyles.display = 'block';
      } else {
        finalStyle = (0, _assign2.default)({}, dialogStyles, _styles2.default.animationBase);
        overlayStyles.display = 'none';
      }

      finalStyle.transitionDuration = this.props.transitionDuration + 'ms';
      overlayStyles.transitionDuration = this.props.transitionDuration + 'ms';

      var overlay = void 0;
      if (this.props.showOverlay) {
        overlay = _react2.default.createElement('div', { className: 'skylight-overlay',
          onClick: function onClick() {
            return _this2.onOverlayClicked();
          },
          style: overlayStyles
        });
      }

      var title = void 0;
      if (_react2.default.isValidElement(this.props.title)) {
        title = this.props.title;
      } else {
        title = this.props.title ? _react2.default.createElement(
          'h2',
          { style: titleStyle },
          this.props.title
        ) : null;
      }

      return _react2.default.createElement(
        'section',
        { className: 'skylight-wrapper' },
        overlay,
        _react2.default.createElement(
          'div',
          { className: 'skylight-dialog', style: finalStyle },
          _react2.default.createElement(
            'a',
            {
              role: 'button',
              className: 'skylight-close-button',
              onClick: function onClick() {
                return _this2.onCloseClicked();
              },
              style: closeButtonStyle
            },
            '\xD7'
          ),
          title,
          this.props.children
        )
      );
    }
  }]);

  return SkyLightStateless;
}(_react2.default.Component);

exports.default = SkyLightStateless;


SkyLightStateless.displayName = 'SkyLightStateless';

SkyLightStateless.sharedPropTypes = {
  closeButtonStyle: _propTypes2.default.object,
  dialogStyles: _propTypes2.default.object,
  onCloseClicked: _propTypes2.default.func,
  onOverlayClicked: _propTypes2.default.func,
  overlayStyles: _propTypes2.default.object,
  showOverlay: _propTypes2.default.bool,
  title: _propTypes2.default.any,
  transitionDuration: _propTypes2.default.number,
  titleStyle: _propTypes2.default.object,
  closeOnEsc: _propTypes2.default.bool
};

SkyLightStateless.propTypes = _extends({}, SkyLightStateless.sharedPropTypes, {
  isVisible: _propTypes2.default.bool
});

SkyLightStateless.defaultProps = {
  title: '',
  showOverlay: true,
  overlayStyles: _styles2.default.overlayStyles,
  dialogStyles: _styles2.default.dialogStyles,
  closeButtonStyle: _styles2.default.closeButtonStyle,
  transitionDuration: 200,
  closeOnEsc: true
};

/***/ }),
/* 209 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(11);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_dom__ = __webpack_require__(104);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_dom___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_react_dom__);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_crowdai_music_evaluation_interface__ = __webpack_require__(210);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_crowdai_music_evaluation_interface___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_crowdai_music_evaluation_interface__);
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb

console.log('Hello World from Webpacker');





/*
document.addEventListener('DOMContentLoaded', () => {
  render(
    <CrowdAIMusicEvaluationInterface name="React" />
    )
  }
)
*/

document.addEventListener('turbolinks:load', function () {
  var musicRoot = document.getElementById('music-root2');
  if (musicRoot) {
    var participantId = musicRoot.dataset.participantId;
    Object(__WEBPACK_IMPORTED_MODULE_1_react_dom__["render"])(__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_2_crowdai_music_evaluation_interface__["CrowdAIMusicEvaluationInterface"], {
      name: 'React', participantId: participantId
    }), musicRoot);
  }
});

/***/ }),
/* 210 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

var _CrowdAIMusicEvaluationInterface = __webpack_require__(211);

Object.defineProperty(exports, 'CrowdAIMusicEvaluationInterface', {
  enumerable: true,
  get: function get() {
    return _interopRequireDefault(_CrowdAIMusicEvaluationInterface).default;
  }
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/***/ }),
/* 211 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _PianoComponent = __webpack_require__(212);

var _PianoComponent2 = _interopRequireDefault(_PianoComponent);

var _MidiPlayerComponent = __webpack_require__(214);

var _MidiPlayerComponent2 = _interopRequireDefault(_MidiPlayerComponent);

__webpack_require__(260);

var _reactSimpleFlexGrid = __webpack_require__(201);

__webpack_require__(202);

var _reactHint = __webpack_require__(261);

var _reactHint2 = _interopRequireDefault(_reactHint);

__webpack_require__(262);

var _axios = __webpack_require__(263);

var _axios2 = _interopRequireDefault(_axios);

var _reactSkylight = __webpack_require__(282);

var _reactSkylight2 = _interopRequireDefault(_reactSkylight);

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 ReactHint = (0, _reactHint2.default)(_react2.default);

var CrowdAIMusicEvaluationInterface = function (_Component) {
  _inherits(CrowdAIMusicEvaluationInterface, _Component);

  function CrowdAIMusicEvaluationInterface(props) {
    _classCallCheck(this, CrowdAIMusicEvaluationInterface);

    var _this = _possibleConstructorReturn(this, (CrowdAIMusicEvaluationInterface.__proto__ || Object.getPrototypeOf(CrowdAIMusicEvaluationInterface)).call(this, props));

    _this.state = {};
    _this.octave = 2;
    _this.max_number_of_piano_keys = 80;

    _this.resetKeyBoard = _this.resetKeyBoard.bind(_this);
    _this.reloadData = _this.reloadData.bind(_this);
    _this.heartClicked = _this.heartClicked.bind(_this);
    _this.OnPlay = _this.OnPlay.bind(_this);
    _this.renderModal = _this.renderModal.bind(_this);
    _this.resetKeyBoard();

    //Modal States
    _this.state.modalLoading = true;
    _this.state.modalWinProbability = 0.5;

    return _this;
  }

  _createClass(CrowdAIMusicEvaluationInterface, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.reloadData();
    }
  }, {
    key: 'heartClicked',
    value: function heartClicked(id) {
      var THIS = this;
      this.setState({ modalLoading: true });
      THIS.simpleDialog.show();
      _axios2.default.post(this.props.base_api_url + "/match/" + this.state.match_id, {
        winner: id
      }).then(function (response) {
        if (response.status === 200) {
          // Pause both the players if they are playing
          if (THIS.refs.midiplayer1.state.hasPlayedOnce) {
            THIS.refs.midiplayer1.pauseSong();
          }
          THIS.refs.midiplayer1.setState({
            isHeartEnabled: false,
            isPlayEnabled: false
          });
          if (THIS.refs.midiplayer0.state.hasPlayedOnce) {
            THIS.refs.midiplayer0.pauseSong();
          }
          THIS.refs.midiplayer0.setState({
            isHeartEnabled: false,
            isPlayEnabled: false
          });
          //Reset Keyboard
          THIS.resetKeyBoard();
          THIS.reloadData();

          THIS.setState({ modalWinProbability: response.data.prob_win, modalLoading: false });
          console.log(response);
        } else {
          // TODO : Add error handling
        }
      }).catch(function (error) {
        console.log(error);
      });
    }
  }, {
    key: 'reloadData',
    value: function reloadData() {
      var THIS = this;
      this.loadingData = true;
      // THIS.refs.midiplayer0.setState({isLoading: true});
      // THIS.refs.midiplayer1.setState({isLoading: true});
      var _state = this.state;
      _state.song1 = false;
      _state.song2 = false;
      _axios2.default.get(this.props.base_api_url + "/match").then(function (response) {
        THIS.loadingData = false;
        THIS.setState({ match_id: response.data.match_id });
        var candidate_1 = response.data.candidate_1;
        _axios2.default.get(candidate_1).then(function (response) {
          THIS.refs.midiplayer0.setState({ submission_id: response.data.key });
          THIS.refs.midiplayer0.load_data_uri(response.data.dataUri);
        });
        var candidate_2 = response.data.candidate_2;
        _axios2.default.get(candidate_2).then(function (response) {
          THIS.refs.midiplayer1.setState({ submission_id: response.data.key });
          THIS.refs.midiplayer1.load_data_uri(response.data.dataUri);
        });
      }).catch(function (error) {
        console.log(error);
      });
    }
  }, {
    key: 'resetKeyBoard',
    value: function resetKeyBoard() {
      var _new_state = {};
      for (var i = 0; i < this.max_number_of_piano_keys; i++) {
        _new_state["key_" + i] = 0;
      }
      this.setState(_new_state);
    }
  }, {
    key: 'OnNoteOn',
    value: function OnNoteOn(noteNumber) {
      if (noteNumber > this.octave * 2 + this.max_number_of_piano_keys) {
        return;
      }
      var key = "key_" + (noteNumber - this.octave * 12);
      var _new_state = {};
      _new_state[key] = 1;
      this.setState(_new_state);
    }
  }, {
    key: 'OnNoteOff',
    value: function OnNoteOff(noteNumber) {
      if (noteNumber > this.octave * 2 + this.max_number_of_piano_keys) {
        return;
      }
      var key = "key_" + (noteNumber - this.octave * 12);
      var _new_state = {};
      _new_state[key] = 0;
      this.setState(_new_state);
    }
  }, {
    key: 'OnPlay',
    value: function OnPlay(playerName) {
      if (playerName === 0) {
        if (this.refs.midiplayer1.state.hasPlayedOnce) {
          this.refs.midiplayer1.pauseSong();
        }
        this.refs.midiplayer0.playSong();
      } else {
        if (this.refs.midiplayer0.state.hasPlayedOnce) {
          this.refs.midiplayer0.pauseSong();
        }
        this.refs.midiplayer1.playSong();
      }
      //Stop all instances
      // this.refs.midiplayer0.pauseSong();
      // this.refs.midiplayer1.pauseSong();
      // midiplayer.playSong();
    }
  }, {
    key: 'renderModal',
    value: function renderModal() {
      var _this2 = this;

      var THIS = this;
      if (this.state.modalLoading) {
        return _react2.default.createElement(
          _reactSimpleFlexGrid.Row,
          { gutter: 10, align: 'middle', justify: 'center' },
          _react2.default.createElement('div', { className: 'crowdai_interface_loader' })
        );
      } else {
        return _react2.default.createElement(
          'div',
          null,
          _react2.default.createElement(
            _reactSimpleFlexGrid.Row,
            { gutter: 10, align: 'middle', justify: 'center' },
            _react2.default.createElement(
              'div',
              { style: { textAlign: "center" } },
              'Your choice had a probability of ',
              _react2.default.createElement(
                'strong',
                null,
                ' ',
                this.state.modalWinProbability,
                ' '
              ),
              ' to be chosen over the other song. ',
              _react2.default.createElement('br', null)
            )
          ),
          _react2.default.createElement(
            _reactSimpleFlexGrid.Row,
            { gutter: 10, align: 'middle', justify: 'center' },
            _react2.default.createElement(
              'button',
              { className: 'crowdai_music_challenge_btns', onClick: function onClick() {
                  _this2.simpleDialog.hide();
                } },
              'Load More Songs'
            )
          )
        );
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this3 = this;

      return _react2.default.createElement(
        'div',
        null,
        _react2.default.createElement(
          _reactSkylight2.default,
          {
            hideOnOverlayClicked: true,
            ref: function ref(_ref) {
              return _this3.simpleDialog = _ref;
            },
            title: '' },
          this.renderModal()
        ),
        _react2.default.createElement(ReactHint, { events: true, delay: 100 }),
        _react2.default.createElement(
          _reactSimpleFlexGrid.Row,
          { className: 'CrowdAIMusicEvaluationInterfaceWrapper', justify: 'left' },
          _react2.default.createElement(
            _reactSimpleFlexGrid.Col,
            { span: 10, offset: 1 },
            _react2.default.createElement(
              _reactSimpleFlexGrid.Row,
              { gutter: 10, align: 'middle', justify: 'center' },
              _react2.default.createElement(
                _reactSimpleFlexGrid.Col,
                { xs: 11, sm: 6, md: 6, lg: 6, xl: 6 },
                _react2.default.createElement(_MidiPlayerComponent2.default, {
                  ref: 'midiplayer0',
                  playerName: 0,
                  dataUri: this.props.song1,
                  onNoteOn: this.OnNoteOn.bind(this),
                  onNoteOff: this.OnNoteOff.bind(this),
                  onPlay: this.OnPlay,
                  onHeartClicked: this.heartClicked,
                  resetKeyBoard: this.resetKeyBoard
                })
              ),
              _react2.default.createElement(
                _reactSimpleFlexGrid.Col,
                { xs: 11, sm: 6, md: 6, lg: 6, xl: 6 },
                _react2.default.createElement(_MidiPlayerComponent2.default, {
                  ref: 'midiplayer1',
                  playerName: 1,
                  dataUri: this.props.song1,
                  onNoteOn: this.OnNoteOn.bind(this),
                  onNoteOff: this.OnNoteOff.bind(this),
                  onPlay: this.OnPlay,
                  onHeartClicked: this.heartClicked,
                  resetKeyBoard: this.resetKeyBoard
                })
              )
            ),
            _react2.default.createElement(
              _reactSimpleFlexGrid.Row,
              { align: 'middle', justify: 'center' },
              _react2.default.createElement(
                _reactSimpleFlexGrid.Col,
                { span: 12 },
                _react2.default.createElement(_PianoComponent2.default, { key_states: this.state, noFloor: true })
              )
            )
          )
        )
      );
    }
  }]);

  return CrowdAIMusicEvaluationInterface;
}(_react.Component);

CrowdAIMusicEvaluationInterface.defaultProps = {
  base_api_url: "https://grader.crowdai.org"
};

exports.default = CrowdAIMusicEvaluationInterface;

/***/ }),
/* 212 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _three = __webpack_require__(192);

var THREE = _interopRequireWildcard(_three);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

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 OrbitControls = require('three-orbit-controls')(THREE)

var ColladaLoader = __webpack_require__(213);
var getCompoundBoundingBox = function getCompoundBoundingBox(object3D) {
  var box = null;
  object3D.traverse(function (obj3D) {
    var geometry = obj3D.geometry;
    if (geometry === undefined) return;
    geometry.computeBoundingBox();
    if (box === null) {
      box = geometry.boundingBox;
    } else {
      box.union(geometry.boundingBox);
    }
  });
  return box;
};

var PianoComponent = function (_React$Component) {
  _inherits(PianoComponent, _React$Component);

  function PianoComponent(props) {
    _classCallCheck(this, PianoComponent);

    var _this = _possibleConstructorReturn(this, (PianoComponent.__proto__ || Object.getPrototypeOf(PianoComponent)).call(this, props));

    _this.props = props;
    _this.state = {
      key_states: _this.props.key_states,
      key_attack_time: _this.props.key_attack_time,
      key_max_rotation: _this.props.key_max_rotation,
      octave: _this.props.octave,
      canvas_id: "canvas_" + parseInt(Math.random() * 10000000, 10)
    };

    _this.init_lights = _this.init_lights.bind(_this);
    _this.prepare_scene = _this.prepare_scene.bind(_this);
    _this.initialize_keys = _this.initialize_keys.bind(_this);
    _this.frame = _this.frame.bind(_this);
    _this.update = _this.update.bind(_this);
    _this.render = _this.render.bind(_this);
    _this.update_key = _this.update_key.bind(_this);
    _this.on_window_resize = _this.on_window_resize.bind(_this);
    _this.smoothstep = _this.smoothstep.bind(_this);
    _this.mix = _this.mix.bind(_this);
    _this.key_status = _this.key_status.bind(_this);

    // this.song = "game_of_thrones.mid";
    _this._noteOnColor = [255, 0, 0, 1.0];
    _this.noteOnColor = new THREE.Color().setRGB(_this._noteOnColor[0] / 256.0, _this._noteOnColor[1] / 256.0, _this._noteOnColor[2] / 256.0);
    _this.keyState = Object.freeze({ unpressed: {}, note_on: {}, pressed: {}, note_off: {} });
    return _this;
  }

  _createClass(PianoComponent, [{
    key: 'frame',
    value: function frame() {
      var delta = this.clock.getDelta();
      this.update(delta);
      this.renderer.render(this.scene, this.camera);
      requestAnimationFrame(this.frame);
      // console.log(this.camera);
    }
  }, {
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.scene = new THREE.Scene();
      this.camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 2.0, 5000);
      window.camera = this.camera;
      this.keys_down = [];
      this.keys_obj = [];
      window.keys_obj = this.keys_obj;

      // window.keyState = this.keyState;
      var canvas = document.getElementById(this.state.canvas_id);
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas: canvas
      });
      // this.renderer.setSize( window.innerWidth, window.innerHeight );
      this.renderer.setSize(document.getElementsByClassName("piano_renderer")[0].clientWidth, document.getElementsByClassName("piano_renderer")[0].clientHeight);
      this.renderer.shadowMapEnabled = true;
      this.renderer.shadowMapSoft = true;
      this.renderer.shadowMapType = THREE.PCFSoftShadowMap;
      this.renderer.gammaInput = true;
      this.renderer.gammaOutput = true;
      this.renderer.physicallyBasedShading = true;
      this.renderer.setClearColor(this.props.backgroundColor, 1);

      // window.THREE = THREE;
      // var axisHelper = new THREE.AxisHelper( 100 );
      // this.scene.add( axisHelper );

      //document.body.appendChild( this.renderer.domElement );
      document.getElementsByClassName("piano_renderer")[0].appendChild(this.renderer.domElement);

      this.material = new THREE.MeshLambertMaterial({ color: 0x606060 });

      if (!this.props.noFloor) {
        this.floor = new THREE.Mesh(new THREE.PlaneBufferGeometry(8000, 8000), new THREE.MeshStandardMaterial({ color: 0xf0f0f0 }));
        // this.floor = new THREE.Mesh( new THREE.PlaneGeometry( 8000, 8000 ), new THREE.MeshBasicMaterial( { color: 0xff00 } ) );
        // this.floor.rotation.x = -90 * ( Math.PI /  180 );
        this.floor.rotation.x = -1 * (Math.PI / 4) - Math.PI / 2;
        this.floor.rotation.y = 0;
        this.floor.rotation.z = 0;
        this.floor.position.y = -0.25;
        this.floor.receiveShadow = true;
        this.floor.castShadow = true;
        this.scene.add(this.floor);
      }
      // this.scene.fog = new THREE.Fog( 0xffffff, 40, 50 );


      var loader = new ColladaLoader();
      loader.load('https://raw.githubusercontent.com/crowdAI/crowdai-music-evaluation-interface/master/src/node_modules/components/PianoComponent/piano.dae', this.prepare_scene);

      this.camera.position.x = 5.802896539348776;
      this.camera.position.y = 13.57757356945138;
      this.camera.position.z = 5.295353133208058;
      this.camera.rotation._x = -1.4064383850715876;
      this.camera.rotation._y = -0.0006859108065163399;
      this.camera.rotation._z = -0.004135604449280542;
      this.camera.quaternion._w = 0.7627631500194035;
      this.camera.quaternion._x = -0.6466745576834863;
      this.camera.quaternion._y = -0.0015987917100707147;
      this.camera.quaternion._z = -0.0013554639102737241;
      this.camera.updateProjectionMatrix();

      // this.cameraControls = new OrbitControls(this.camera);

      this.clock = new THREE.Clock();

      this.init_lights();

      this.frame();
      window.addEventListener('resize', this.on_window_resize, true);
      this.on_window_resize();
    }
  }, {
    key: 'on_window_resize',
    value: function on_window_resize() {
      this.camera.aspect = document.getElementsByClassName("piano_renderer")[0].clientWidth / document.getElementsByClassName("piano_renderer")[0].clientHeight;
      this.renderer.setSize(document.getElementsByClassName("piano_renderer")[0].clientWidth, document.getElementsByClassName("piano_renderer")[0].clientHeight);
      this.camera.updateProjectionMatrix();
    }
  }, {
    key: 'update',
    value: function update(delta) {
      window.camera = this.camera;
      for (var i in this.keys_obj) {
        this.update_key(this.keys_obj[i], delta);
      }
    }
  }, {
    key: 'smoothstep',
    value: function smoothstep(a, b, x) {
      if (x < a) return 0.0;
      if (x > b) return 1.0;
      var y = (x - a) / (b - a);
      return y * y * (3.0 - 2.0 * y);
    }
  }, {
    key: 'mix',
    value: function mix(a, b, x) {
      return a + (b - a) * Math.min(Math.max(x, 0.0), 1.0);
    }
  }, {
    key: 'update_key',
    value: function update_key(obj, delta) {
      if (obj.keyState === this.keyState.note_on) {

        obj.rotation.x = this.mix(-Math.PI / 4.0, -this.state.key_max_rotation, this.smoothstep(0.0, 1.0, this.state.key_attack_time * obj.clock.getElapsedTime()));
        if (obj.rotation.x >= -this.state.key_max_rotation) {
          obj.keyState = this.keyState.pressed;
          obj.clock.elapsedTime = 0;
        }

        if (obj.children.length > 0) {
          obj.children[0].material.color = this.noteOnColor;
        }
      } else if (obj.keyState === this.keyState.note_off) {
        obj.rotation.x = this.mix(-this.state.key_max_rotation, -Math.PI / 4.0, this.smoothstep(0.0, 1.0, this.state.key_attack_time * obj.clock.getElapsedTime()));
        if (obj.rotation.x <= -Math.PI / 4.0) {
          obj.keyState = this.keyState.unpressed;
          obj.clock.elapsedTime = 0;
        }

        if (obj.children.length > 0) {
          obj.children[0].material.color = obj.children[0].material.note_off;
        }
      }
    }
  }, {
    key: 'key_status',
    value: function key_status(keyName, status) {
      if (this.scene) {
        var obj = this.scene.getObjectByName(keyName, true);
        if (obj !== undefined) {
          obj.clock.start();
          obj.clock.elapsedTime = 0;
          obj.keyState = status;
        }
      }
    }
  }, {
    key: 'initialize_keys',
    value: function initialize_keys(obj) {
      this.keys_obj.push(obj);
      obj.castShadow = true;
      obj.receiveShadow = true;
      obj.rotation.x = -Math.PI / 4.0;
      // obj.rotation.x = 0;
      obj.rotation.y = 0;
      obj.rotation.z = 0;
      obj.keyState = this.keyState.unpressed;
      obj.clock = new THREE.Clock(false);
      obj.castShadow = true;
      obj.receiveShadow = true;
      // only add meshes in the material redefinition (to make keys change their color when pressed)
      if (obj instanceof THREE.Mesh) {
        var old_material = obj.material;
        obj.material = new THREE.MeshPhongMaterial({ color: old_material.color });
        obj.material.shininess = 100.0;
        obj.material.specular = new THREE.Color().setRGB(0.25, 0.25, 0.25);;

        obj.material.note_off = obj.material.color.clone();
      }
    }
  }, {
    key: 'fix_zoom',
    value: function fix_zoom() {
      var boundingBox = getCompoundBoundingBox(this.collada_scene);
      this.camera.zoom = 10;
      this.camera.updateMatrix();
      for (var i = 0; i < 1000; i += 1) {
        if (this.camera.zoom <= 0.5) {
          break;
        }
        this.camera.zoom -= 0.1;
        this.camera.updateProjectionMatrix();
        var frustum = new THREE.Frustum();
        frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse));

        var pos_min = new THREE.Vector3(boundingBox.min.x, boundingBox.min.y, boundingBox.min.z);
        var pos_max = new THREE.Vector3(boundingBox.min.x, boundingBox.min.y, boundingBox.min.z);

        if (frustum.containsPoint(pos_min) && frustum.containsPoint(pos_max)) {
          break;
        }
      }
    }
  }, {
    key: 'prepare_scene',
    value: function prepare_scene(collada) {
      collada.scene.traverse(this.initialize_keys);
      this.collada_scene = collada.scene;
      this.scene.add(collada.scene);
      // this.fix_zoom();
    }
  }, {
    key: 'init_lights',
    value: function init_lights() {
      //var spotlight = new THREE.SpotLight(0xffffff);
      var spotlight = new THREE.DirectionalLight(0xffffff);

      // spotlight.position.set(-10,10,-20);
      spotlight.position.set(-1, 1, -2);

      var targetObject = new THREE.Object3D();
      targetObject.position.x = 10;
      targetObject.position.y = 0;
      targetObject.position.z = 4;
      spotlight.target = targetObject;
      this.scene.add(targetObject);
      // window.keys_obj = this.keys_obj
      // spotlight.target.position.set(10, 10, -10);
      spotlight.shadowCameraVisible = true;
      spotlight.shadowDarkness = 0.75;
      spotlight.intensity = 1;
      spotlight.castShadow = true;
      spotlight.shadowMapWidth = 2048;
      spotlight.shadowMapHeight = 2048;

      // spotlight.shadowCameraNear = 5.0;
      // spotlight.shadowCameraFar = 20.0;
      spotlight.shadowBias = 0.0025;
      window.scene = this.scene;

      // spotlight.shadowCameraLeft = -8.85;
      // spotlight.shadowCameraRight = 5.5;
      // spotlight.shadowCameraTop = 4;
      // spotlight.shadowCameraBottom = 0;
      this.scene.add(spotlight);

      // var helper = new THREE.CameraHelper( spotlight.shadow.camera );
      // this.scene.add( helper );

      var light1 = new THREE.DirectionalLight(0xddffff, 1);
      light1.position.set(1, 1, -1).normalize();
      this.scene.add(light1);

      var light3 = new THREE.AmbientLight(0xffffff, 0.1);
      light3.position.set(0, 0, 10).normalize();
      this.scene.add(light3);
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      var _temp = {};
      Object.keys(this.props.key_states).map(function (i) {
        if (i.startsWith("key_")) {
          if (_this2.last_state) {
            if (_this2.last_state[i] === 0 && _this2.props.key_states[i] === 1) {
              _this2.key_status("_" + i.replace("key_", ""), _this2.keyState.note_on);
            } else if (_this2.last_state[i] === 1 && _this2.props.key_states[i] === 0) {
              _this2.key_status("_" + i.replace("key_", ""), _this2.keyState.note_off);
            }
          }
          _temp[i] = _this2.props.key_states[i];
        }
        return _this2.props.key_states;
      });
      this.last_state = _temp;
      return _react2.default.createElement(
        'div',
        { className: 'piano_renderer' },
        _react2.default.createElement('canvas', { id: this.state.canvas_id, style: { width: "100%", height: "100%" } })
      );
    }
  }]);

  return PianoComponent;
}(_react2.default.Component);

PianoComponent.defaultProps = {
  key_states: {},
  key_attack_time: 9.0,
  key_max_rotation: 0.72,
  octave: 2,
  noFloor: false,
  backgroundColor: 0xffffff
};
exports.default = PianoComponent;

/***/ }),
/* 213 */
/***/ (function(module, exports, __webpack_require__) {

var THREE = __webpack_require__( 192 );

/**
* @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com
* @author Tony Parisi / http://www.tonyparisi.com/
*/

var ColladaLoader = function () {

    var COLLADA = null;
    var scene = null;
    var visualScene;
    var kinematicsModel;

    var readyCallbackFunc = null;

    var sources = {};
    var images = {};
    var animations = {};
    var controllers = {};
    var geometries = {};
    var materials = {};
    var effects = {};
    var cameras = {};
    var lights = {};

    var animData;
    var kinematics;
    var visualScenes;
    var kinematicsModels;
    var baseUrl;
    var morphs;
    var skins;

    var flip_uv = true;
    var preferredShading = THREE.SmoothShading;

    var options = {
        // Force Geometry to always be centered at the local origin of the
        // containing Mesh.
        centerGeometry: false,

        // Axis conversion is done for geometries, animations, and controllers.
        // If we ever pull cameras or lights out of the COLLADA file, they'll
        // need extra work.
        convertUpAxis: false,

        subdivideFaces: true,

        upAxis: 'Y',

        // For reflective or refractive materials we'll use this cubemap
        defaultEnvMap: null

    };

    var colladaUnit = 1.0;
    var colladaUp = 'Y';
    var upConversion = null;

    function load ( url, readyCallback, progressCallback, failCallback ) {

        var length = 0;

        if ( document.implementation && document.implementation.createDocument ) {

            var request = new XMLHttpRequest();

            request.onreadystatechange = function() {

                if ( request.readyState === 4 ) {

                    if ( request.status === 0 || request.status === 200 ) {

                        if ( request.response ) {

                            readyCallbackFunc = readyCallback;
                            parse( request.response, undefined, url );

                        } else {

                            if ( failCallback ) {

                                failCallback();

                            } else {

                                console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" );

                            }

                        }

                    }

                } else if ( request.readyState === 3 ) {

                    if ( progressCallback ) {

                        if ( length === 0 ) {

                            length = request.getResponseHeader( "Content-Length" );

                        }

                        progressCallback( { total: length, loaded: request.responseText.length } );

                    }

                }

            };

            request.open( "GET", url, true );
            request.send( null );

        } else {

            alert( "Don't know how to parse XML!" );

        }

    }

    function parse( text, callBack, url ) {

        COLLADA = new DOMParser().parseFromString( text, 'text/xml' );
        callBack = callBack || readyCallbackFunc;

        if ( url !== undefined ) {

            var parts = url.split( '/' );
            parts.pop();
            baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';

        }

        parseAsset();
        setUpConversion();
        images = parseLib( "library_images image", _Image, "image" );
        materials = parseLib( "library_materials material", Material, "material" );
        effects = parseLib( "library_effects effect", Effect, "effect" );
        geometries = parseLib( "library_geometries geometry", Geometry, "geometry" );
        cameras = parseLib( "library_cameras camera", Camera, "camera" );
        lights = parseLib( "library_lights light", Light, "light" );
        controllers = parseLib( "library_controllers controller", Controller, "controller" );
        animations = parseLib( "library_animations animation", Animation, "animation" );
        visualScenes = parseLib( "library_visual_scenes visual_scene", VisualScene, "visual_scene" );
        kinematicsModels = parseLib( "library_kinematics_models kinematics_model", KinematicsModel, "kinematics_model" );

        morphs = [];
        skins = [];

        visualScene = parseScene();
        scene = new THREE.Group();

        for ( var i = 0; i < visualScene.nodes.length; i ++ ) {

            scene.add( createSceneGraph( visualScene.nodes[ i ] ) );

        }

        // unit conversion
        scene.scale.multiplyScalar( colladaUnit );

        createAnimations();

        kinematicsModel = parseKinematicsModel();
        createKinematics();

        var result = {

            scene: scene,
            morphs: morphs,
            skins: skins,
            animations: animData,
            kinematics: kinematics,
            dae: {
                images: images,
                materials: materials,
                cameras: cameras,
                lights: lights,
                effects: effects,
                geometries: geometries,
                controllers: controllers,
                animations: animations,
                visualScenes: visualScenes,
                visualScene: visualScene,
                scene: visualScene,
                kinematicsModels: kinematicsModels,
                kinematicsModel: kinematicsModel
            }

        };

        if ( callBack ) {

            callBack( result );

        }

        return result;

    }

    function setPreferredShading ( shading ) {

        preferredShading = shading;

    }

    function parseAsset () {

        var elements = COLLADA.querySelectorAll('asset');

        var element = elements[0];

        if ( element && element.childNodes ) {

            for ( var i = 0; i < element.childNodes.length; i ++ ) {

                var child = element.childNodes[ i ];

                switch ( child.nodeName ) {

                    case 'unit':

                        var meter = child.getAttribute( 'meter' );

                        if ( meter ) {

                            colladaUnit = parseFloat( meter );

                        }

                        break;

                    case 'up_axis':

                        colladaUp = child.textContent.charAt(0);
                        break;

                }

            }

        }

    }

    function parseLib ( q, classSpec, prefix ) {

        var elements = COLLADA.querySelectorAll(q);

        var lib = {};

        var i = 0;

        var elementsLength = elements.length;

        for ( var j = 0; j < elementsLength; j ++ ) {

            var element = elements[j];
            var daeElement = ( new classSpec() ).parse( element );

            if ( !daeElement.id || daeElement.id.length === 0 ) daeElement.id = prefix + ( i ++ );
            lib[ daeElement.id ] = daeElement;

        }

        return lib;

    }

    function parseScene() {

        var sceneElement = COLLADA.querySelectorAll('scene instance_visual_scene')[0];

        if ( sceneElement ) {

            var url = sceneElement.getAttribute( 'url' ).replace( /^#/, '' );
            return visualScenes[ url.length > 0 ? url : 'visual_scene0' ];

        } else {

            return null;

        }

    }

    function parseKinematicsModel() {

        var kinematicsModelElement = COLLADA.querySelectorAll('instance_kinematics_model')[0];

        if ( kinematicsModelElement ) {

            var url = kinematicsModelElement.getAttribute( 'url' ).replace(/^#/, '');
            return kinematicsModels[ url.length > 0 ? url : 'kinematics_model0' ];

        } else {

            return null;

        }

    }

    function createAnimations() {

        animData = [];

        // fill in the keys
        recurseHierarchy( scene );

    }

    function recurseHierarchy( node ) {

        var n = visualScene.getChildById( node.colladaId, true ),
            newData = null;

        if ( n && n.keys ) {

            newData = {
                fps: 60,
                hierarchy: [ {
                    node: n,
                    keys: n.keys,
                    sids: n.sids
                } ],
                node: node,
                name: 'animation_' + node.name,
                length: 0
            };

            animData.push(newData);

            for ( var i = 0, il = n.keys.length; i < il; i ++ ) {

                newData.length = Math.max( newData.length, n.keys[i].time );

            }

        } else {

            newData = {
                hierarchy: [ {
                    keys: [],
                    sids: []
                } ]
            }

        }

        for ( var i = 0, il = node.children.length; i < il; i ++ ) {

            var d = recurseHierarchy( node.children[i] );

            for ( var j = 0, jl = d.hierarchy.length; j < jl; j ++ ) {

                newData.hierarchy.push( {
                    keys: [],
                    sids: []
                } );

            }

        }

        return newData;

    }

    function calcAnimationBounds () {

        var start = 1000000;
        var end = -start;
        var frames = 0;
        var ID;
        for ( var id in animations ) {

            var animation = animations[ id ];
            ID = ID || animation.id;
            for ( var i = 0; i < animation.sampler.length; i ++ ) {

                var sampler = animation.sampler[ i ];

                sampler.create();

                start = Math.min( start, sampler.startTime );
                end = Math.max( end, sampler.endTime );
                frames = Math.max( frames, sampler.input.length );

            }

        }

        return { start:start, end:end, frames:frames,ID:ID };

    }

    function createMorph ( geometry, ctrl ) {

        var morphCtrl = ctrl instanceof InstanceController ? controllers[ ctrl.url ] : ctrl;

        if ( !morphCtrl || !morphCtrl.morph ) {

            console.log("could not find morph controller!");
            return;

        }

        var morph = morphCtrl.morph;

        for ( var i = 0; i < morph.targets.length; i ++ ) {

            var target_id = morph.targets[ i ];
            var daeGeometry = geometries[ target_id ];

            if ( !daeGeometry.mesh ||
                 !daeGeometry.mesh.primitives ||
                 !daeGeometry.mesh.primitives.length ) {
                 continue;
            }

            var target = daeGeometry.mesh.primitives[ 0 ].geometry;

            if ( target.vertices.length === geometry.vertices.length ) {

                geometry.morphTargets.push( { name: "target_1", vertices: target.vertices } );

            }

        }

        geometry.morphTargets.push( { name: "target_Z", vertices: geometry.vertices } );

    }

    function createSkin ( geometry, ctrl, applyBindShape ) {

        var skinCtrl = controllers[ ctrl.url ];

        if ( !skinCtrl || !skinCtrl.skin ) {

            console.log( "could not find skin controller!" );
            return;

        }

        if ( !ctrl.skeleton || !ctrl.skeleton.length ) {

            console.log( "could not find the skeleton for the skin!" );
            return;

        }

        var skin = skinCtrl.skin;
        var skeleton = visualScene.getChildById( ctrl.skeleton[ 0 ] );
        var hierarchy = [];

        applyBindShape = applyBindShape !== undefined ? applyBindShape : true;

        var bones = [];
        geometry.skinWeights = [];
        geometry.skinIndices = [];

        //createBones( geometry.bones, skin, hierarchy, skeleton, null, -1 );
        //createWeights( skin, geometry.bones, geometry.skinIndices, geometry.skinWeights );

        /*
        geometry.animation = {
            name: 'take_001',
            fps: 30,
            length: 2,
            JIT: true,
            hierarchy: hierarchy
        };
        */

        if ( applyBindShape ) {

            for ( var i = 0; i < geometry.vertices.length; i ++ ) {

                geometry.vertices[ i ].applyMatrix4( skin.bindShapeMatrix );

            }

        }

    }

    function setupSkeleton ( node, bones, frame, parent ) {

        node.world = node.world || new THREE.Matrix4();
        node.localworld = node.localworld || new THREE.Matrix4();
        node.world.copy( node.matrix );
        node.localworld.copy( node.matrix );

        if ( node.channels && node.channels.length ) {

            var channel = node.channels[ 0 ];
            var m = channel.sampler.output[ frame ];

            if ( m instanceof THREE.Matrix4 ) {

                node.world.copy( m );
                node.localworld.copy(m);
                if (frame === 0)
                    node.matrix.copy(m);
            }

        }

        if ( parent ) {

            node.world.multiplyMatrices( parent, node.world );

        }

        bones.push( node );

        for ( var i = 0; i < node.nodes.length; i ++ ) {

            setupSkeleton( node.nodes[ i ], bones, frame, node.world );

        }

    }

    function setupSkinningMatrices ( bones, skin ) {

        // FIXME: this is dumb...

        for ( var i = 0; i < bones.length; i ++ ) {

            var bone = bones[ i ];
            var found = -1;

            if ( bone.type != 'JOINT' ) continue;

            for ( var j = 0; j < skin.joints.length; j ++ ) {

                if ( bone.sid === skin.joints[ j ] ) {

                    found = j;
                    break;

                }

            }

            if ( found >= 0 ) {

                var inv = skin.invBindMatrices[ found ];

                bone.invBindMatrix = inv;
                bone.skinningMatrix = new THREE.Matrix4();
                bone.skinningMatrix.multiplyMatrices(bone.world, inv); // (IBMi * JMi)
                bone.animatrix = new THREE.Matrix4();

                bone.animatrix.copy(bone.localworld);
                bone.weights = [];

                for ( var j = 0; j < skin.weights.length; j ++ ) {

                    for (var k = 0; k < skin.weights[ j ].length; k ++ ) {

                        var w = skin.weights[ j ][ k ];

                        if ( w.joint === found ) {

                            bone.weights.push( w );

                        }

                    }

                }

            } else {

                console.warn( "ColladaLoader: Could not find joint '" + bone.sid + "'." );

                bone.skinningMatrix = new THREE.Matrix4();
                bone.weights = [];

            }
        }

    }

    //Walk the Collada tree and flatten the bones into a list, extract the position, quat and scale from the matrix
    function flattenSkeleton(skeleton) {

        var list = [];
        var walk = function(parentid, node, list) {

            var bone = {};
            bone.name = node.sid;
            bone.parent = parentid;
            bone.matrix = node.matrix;
            var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];
            bone.matrix.decompose(data[0], data[1], data[2]);

            bone.pos = [ data[0].x,data[0].y,data[0].z ];

            bone.scl = [ data[2].x,data[2].y,data[2].z ];
            bone.rotq = [ data[1].x,data[1].y,data[1].z,data[1].w ];
            list.push(bone);

            for (var i in node.nodes) {

                walk(node.sid, node.nodes[i], list);

            }

        };

        walk(-1, skeleton, list);
        return list;

    }

    //Move the vertices into the pose that is proper for the start of the animation
    function skinToBindPose(geometry,skeleton,skinController) {

        var bones = [];
        setupSkeleton( skeleton, bones, -1 );
        setupSkinningMatrices( bones, skinController.skin );
        var v = new THREE.Vector3();
        var skinned = [];

        for (var i = 0; i < geometry.vertices.length; i ++) {

            skinned.push(new THREE.Vector3());

        }

        for ( i = 0; i < bones.length; i ++ ) {

            if ( bones[ i ].type != 'JOINT' ) continue;

            for ( var j = 0; j < bones[ i ].weights.length; j ++ ) {

                var w = bones[ i ].weights[ j ];
                var vidx = w.index;
                var weight = w.weight;

                var o = geometry.vertices[vidx];
                var s = skinned[vidx];

                v.x = o.x;
                v.y = o.y;
                v.z = o.z;

                v.applyMatrix4( bones[i].skinningMatrix );

                s.x += (v.x * weight);
                s.y += (v.y * weight);
                s.z += (v.z * weight);
            }

        }

        for (var i = 0; i < geometry.vertices.length; i ++) {

            geometry.vertices[i] = skinned[i];

        }

    }

    function applySkin ( geometry, instanceCtrl, frame ) {

        var skinController = controllers[ instanceCtrl.url ];

        frame = frame !== undefined ? frame : 40;

        if ( !skinController || !skinController.skin ) {

            console.log( 'ColladaLoader: Could not find skin controller.' );
            return;

        }

        if ( !instanceCtrl.skeleton || !instanceCtrl.skeleton.length ) {

            console.log( 'ColladaLoader: Could not find the skeleton for the skin. ' );
            return;

        }

        var animationBounds = calcAnimationBounds();
        var skeleton = visualScene.getChildById( instanceCtrl.skeleton[0], true ) || visualScene.getChildBySid( instanceCtrl.skeleton[0], true );

        //flatten the skeleton into a list of bones
        var bonelist = flattenSkeleton(skeleton);
        var joints = skinController.skin.joints;

        //sort that list so that the order reflects the order in the joint list
        var sortedbones = [];
        for (var i = 0; i < joints.length; i ++) {

            for (var j = 0; j < bonelist.length; j ++) {

                if (bonelist[j].name === joints[i]) {

                    sortedbones[i] = bonelist[j];

                }

            }

        }

        //hook up the parents by index instead of name
        for (var i = 0; i < sortedbones.length; i ++) {

            for (var j = 0; j < sortedbones.length; j ++) {

                if (sortedbones[i].parent === sortedbones[j].name) {

                    sortedbones[i].parent = j;

                }

            }

        }


        var i, j, w, vidx, weight;
        var v = new THREE.Vector3(), o, s;

        // move vertices to bind shape
        for ( i = 0; i < geometry.vertices.length; i ++ ) {
            geometry.vertices[i].applyMatrix4( skinController.skin.bindShapeMatrix );
        }

        var skinIndices = [];
        var skinWeights = [];
        var weights = skinController.skin.weights;

        // hook up the skin weights
        // TODO - this might be a good place to choose greatest 4 weights
        for ( var i =0; i < weights.length; i ++ ) {

            var indicies = new THREE.Vector4(weights[i][0] ? weights[i][0].joint : 0,weights[i][1] ? weights[i][1].joint : 0,weights[i][2] ? weights[i][2].joint : 0,weights[i][3] ? weights[i][3].joint : 0);
            var weight = new THREE.Vector4(weights[i][0] ? weights[i][0].weight : 0,weights[i][1] ? weights[i][1].weight : 0,weights[i][2] ? weights[i][2].weight : 0,weights[i][3] ? weights[i][3].weight : 0);

            skinIndices.push(indicies);
            skinWeights.push(weight);

        }

        geometry.skinIndices = skinIndices;
        geometry.skinWeights = skinWeights;
        geometry.bones = sortedbones;
        // process animation, or simply pose the rig if no animation

        //create an animation for the animated bones
        //NOTE: this has no effect when using morphtargets
        var animationdata = { "name":animationBounds.ID,"fps":30,"length":animationBounds.frames / 30,"hierarchy":[] };

        for (var j = 0; j < sortedbones.length; j ++) {

            animationdata.hierarchy.push({ parent:sortedbones[j].parent, name:sortedbones[j].name, keys:[] });

        }

        console.log( 'ColladaLoader:', animationBounds.ID + ' has ' + sortedbones.length + ' bones.' );



        skinToBindPose(geometry, skeleton, skinController);


        for ( frame = 0; frame < animationBounds.frames; frame ++ ) {

            var bones = [];
            var skinned = [];
            // process the frame and setup the rig with a fresh
            // transform, possibly from the bone's animation channel(s)

            setupSkeleton( skeleton, bones, frame );
            setupSkinningMatrices( bones, skinController.skin );

            for (var i = 0; i < bones.length; i ++) {

                for (var j = 0; j < animationdata.hierarchy.length; j ++) {

                    if (animationdata.hierarchy[j].name === bones[i].sid) {

                        var key = {};
                        key.time = (frame / 30);
                        key.matrix = bones[i].animatrix;

                        if (frame === 0)
                            bones[i].matrix = key.matrix;

                        var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];
                        key.matrix.decompose(data[0], data[1], data[2]);

                        key.pos = [ data[0].x,data[0].y,data[0].z ];

                        key.scl = [ data[2].x,data[2].y,data[2].z ];
                        key.rot = data[1];

                        animationdata.hierarchy[j].keys.push(key);

                    }

                }

            }

            geometry.animation = animationdata;

        }

    }

    function createKinematics() {

        if ( kinematicsModel && kinematicsModel.joints.length === 0 ) {
            kinematics = undefined;
            return;
        }

        var jointMap = {};

        var _addToMap = function( jointIndex, parentVisualElement ) {

            var parentVisualElementId = parentVisualElement.getAttribute( 'id' );
            var colladaNode = visualScene.getChildById( parentVisualElementId, true );
            var joint = kinematicsModel.joints[ jointIndex ];

            scene.traverse(function( node ) {

                if ( node.colladaId == parentVisualElementId ) {

                    jointMap[ jointIndex ] = {
                        node: node,
                        transforms: colladaNode.transforms,
                        joint: joint,
                        position: joint.zeroPosition
                    };

                }

            });

        };

        kinematics = {

            joints: kinematicsModel && kinematicsModel.joints,

            getJointValue: function( jointIndex ) {

                var jointData = jointMap[ jointIndex ];

                if ( jointData ) {

                    return jointData.position;

                } else {

                    console.log( 'getJointValue: joint ' + jointIndex + ' doesn\'t exist' );

                }

            },

            setJointValue: function( jointIndex, value ) {

                var jointData = jointMap[ jointIndex ];

                if ( jointData ) {

                    var joint = jointData.joint;

                    if ( value > joint.limits.max || value < joint.limits.min ) {

                        console.log( 'setJointValue: joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ')' );

                    } else if ( joint.static ) {

                        console.log( 'setJointValue: joint ' + jointIndex + ' is static' );

                    } else {

                        var threejsNode = jointData.node;
                        var axis = joint.axis;
                        var transforms = jointData.transforms;

                        var matrix = new THREE.Matrix4();

                        for (i = 0; i < transforms.length; i ++ ) {

                            var transform = transforms[ i ];

                            // kinda ghetto joint detection
                            if ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) {

                                // apply actual joint value here
                                switch ( joint.type ) {

                                    case 'revolute':

                                        matrix.multiply( m1.makeRotationAxis( axis, THREE.Math.degToRad(value) ) );
                                        break;

                                    case 'prismatic':

                                        matrix.multiply( m1.makeTranslation(axis.x * value, axis.y * value, axis.z * value ) );
                                        break;

                                    default:

                                        console.warn( 'setJointValue: unknown joint type: ' + joint.type );
                                        break;

                                }

                            } else {

                                var m1 = new THREE.Matrix4();

                                switch ( transform.type ) {

                                    case 'matrix':

                                        matrix.multiply( transform.obj );

                                        break;

                                    case 'translate':

                                        matrix.multiply( m1.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );

                                        break;

                                    case 'rotate':

                                        matrix.multiply( m1.makeRotationAxis( transform.obj, transform.angle ) );

                                        break;

                                }
                            }
                        }

                        // apply the matrix to the threejs node
                        var elementsFloat32Arr = matrix.elements;
                        var elements = Array.prototype.slice.call( elementsFloat32Arr );

                        var elementsRowMajor = [
                            elements[ 0 ],
                            elements[ 4 ],
                            elements[ 8 ],
                            elements[ 12 ],
                            elements[ 1 ],
                            elements[ 5 ],
                            elements[ 9 ],
                            elements[ 13 ],
                            elements[ 2 ],
                            elements[ 6 ],
                            elements[ 10 ],
                            elements[ 14 ],
                            elements[ 3 ],
                            elements[ 7 ],
                            elements[ 11 ],
                            elements[ 15 ]
                        ];

                        threejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor );
                        threejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale );
                    }

                } else {

                    console.log( 'setJointValue: joint ' + jointIndex + ' doesn\'t exist' );

                }

            }

        };

        var element = COLLADA.querySelector('scene instance_kinematics_scene');

        if ( element ) {

            for ( var i = 0; i < element.childNodes.length; i ++ ) {

                var child = element.childNodes[ i ];

                if ( child.nodeType != 1 ) continue;

                switch ( child.nodeName ) {

                    case 'bind_joint_axis':

                        var visualTarget = child.getAttribute( 'target' ).split( '/' ).pop();
                        var axis = child.querySelector('axis param').textContent;
                        var jointIndex = parseInt( axis.split( 'joint' ).pop().split( '.' )[0] );
                        var visualTargetElement = COLLADA.querySelector( '[sid="' + visualTarget + '"]' );

                        if ( visualTargetElement ) {
                            var parentVisualElement = visualTargetElement.parentElement;
                            _addToMap(jointIndex, parentVisualElement);
                        }

                        break;

                    default:

                        break;

                }

            }
        }

    }

    function createSceneGraph ( node, parent ) {

        var obj = new THREE.Object3D();
        var skinned = false;
        var skinController;
        var morphController;
        var i, j;

        // FIXME: controllers

        for ( i = 0; i < node.controllers.length; i ++ ) {

            var controller = controllers[ node.controllers[ i ].url ];

            switch ( controller.type ) {

                case 'skin':

                    if ( geometries[ controller.skin.source ] ) {

                        var inst_geom = new InstanceGeometry();

                        inst_geom.url = controller.skin.source;
                        inst_geom.instance_material = node.controllers[ i ].instance_material;

                        node.geometries.push( inst_geom );
                        skinned = true;
                        skinController = node.controllers[ i ];

                    } else if ( controllers[ controller.skin.source ] ) {

                        // urgh: controller can be chained
                        // handle the most basic case...

                        var second = controllers[ controller.skin.source ];
                        morphController = second;
                    //    skinController = node.controllers[i];

                        if ( second.morph && geometries[ second.morph.source ] ) {

                            var inst_geom = new InstanceGeometry();

                            inst_geom.url = second.morph.source;
                            inst_geom.instance_material = node.controllers[ i ].instance_material;

                            node.geometries.push( inst_geom );

                        }

                    }

                    break;

                case 'morph':

                    if ( geometries[ controller.morph.source ] ) {

                        var inst_geom = new InstanceGeometry();

                        inst_geom.url = controller.morph.source;
                        inst_geom.instance_material = node.controllers[ i ].instance_material;

                        node.geometries.push( inst_geom );
                        morphController = node.controllers[ i ];

                    }

                    console.log( 'ColladaLoader: Morph-controller partially supported.' );

                default:
                    break;

            }

        }

        // geometries

        var double_sided_materials = {};

        for ( i = 0; i < node.geometries.length; i ++ ) {

            var instance_geometry = node.geometries[i];
            var instance_materials = instance_geometry.instance_material;
            var geometry = geometries[ instance_geometry.url ];
            var used_materials = {};
            var used_materials_array = [];
            var num_materials = 0;
            var first_material;

            if ( geometry ) {

                if ( !geometry.mesh || !geometry.mesh.primitives )
                    continue;

                if ( obj.name.length === 0 ) {

                    obj.name = geometry.id;

                }

                // collect used fx for this geometry-instance

                if ( instance_materials ) {

                    for ( j = 0; j < instance_materials.length; j ++ ) {

                        var instance_material = instance_materials[ j ];
                        var mat = materials[ instance_material.target ];
                        var effect_id = mat.instance_effect.url;
                        var shader = effects[ effect_id ].shader;
                        var material3js = shader.material;

                        if ( geometry.doubleSided ) {

                            if ( !( instance_material.symbol in double_sided_materials ) ) {

                                var _copied_material = material3js.clone();
                                _copied_material.side = THREE.DoubleSide;
                                double_sided_materials[ instance_material.symbol ] = _copied_material;

                            }

                            material3js = double_sided_materials[ instance_material.symbol ];

                        }

                        material3js.opacity = !material3js.opacity ? 1 : material3js.opacity;
                        used_materials[ instance_material.symbol ] = num_materials;
                        used_materials_array.push( material3js );
                        first_material = material3js;
                        first_material.name = mat.name === null || mat.name === '' ? mat.id : mat.name;
                        num_materials ++;

                    }

                }

                var mesh;
                var material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } );
                var geom = geometry.mesh.geometry3js;

                if ( num_materials > 1 ) {

                    material = new THREE.MultiMaterial( used_materials_array );

                }

                if ( skinController !== undefined ) {


                    applySkin( geom, skinController );

                    if ( geom.morphTargets.length > 0 ) {

                        material.morphTargets = true;
                        material.skinning = false;

                    } else {

                        material.morphTargets = false;
                        material.skinning = true;

                    }


                    mesh = new THREE.SkinnedMesh( geom, material, false );


                    //mesh.skeleton = skinController.skeleton;
                    //mesh.skinController = controllers[ skinController.url ];
                    //mesh.skinInstanceController = skinController;
                    mesh.name = 'skin_' + skins.length;



                    //mesh.animationHandle.setKey(0);
                    skins.push( mesh );

                } else if ( morphController !== undefined ) {

                    createMorph( geom, morphController );

                    material.morphTargets = true;

                    mesh = new THREE.Mesh( geom, material );
                    mesh.name = 'morph_' + morphs.length;

                    morphs.push( mesh );

                } else {

                    if ( geom.isLineStrip === true ) {

                        mesh = new THREE.Line( geom );

                    } else {

                        mesh = new THREE.Mesh( geom, material );

                    }

                }

                obj.add(mesh);

            }

        }

        for ( i = 0; i < node.cameras.length; i ++ ) {

            var instance_camera = node.cameras[i];
            var cparams = cameras[instance_camera.url];

            var cam = new THREE.PerspectiveCamera(cparams.yfov, parseFloat(cparams.aspect_ratio),
                    parseFloat(cparams.znear), parseFloat(cparams.zfar));

            obj.add(cam);
        }

        for ( i = 0; i < node.lights.length; i ++ ) {

            var light = null;
            var instance_light = node.lights[i];
            var lparams = lights[instance_light.url];

            if ( lparams && lparams.technique ) {

                var color = lparams.color.getHex();
                var intensity = lparams.intensity;
                var distance = lparams.distance;
                var angle = lparams.falloff_angle;

                switch ( lparams.technique ) {

                    case 'directional':

                        light = new THREE.DirectionalLight( color, intensity, distance );
                        light.position.set(0, 0, 1);
                        break;

                    case 'point':

                        light = new THREE.PointLight( color, intensity, distance );
                        break;

                    case 'spot':

                        light = new THREE.SpotLight( color, intensity, distance, angle );
                        light.position.set(0, 0, 1);
                        break;

                    case 'ambient':

                        light = new THREE.AmbientLight( color );
                        break;

                }

            }

            if (light) {
                obj.add(light);
            }
        }

        obj.name = node.name || node.id || "";
        obj.colladaId = node.id || "";
        obj.layer = node.layer || "";
        obj.matrix = node.matrix;
        obj.matrix.decompose( obj.position, obj.quaternion, obj.scale );

        if ( options.centerGeometry && obj.geometry ) {

            var delta = obj.geometry.center();
            delta.multiply( obj.scale );
            delta.applyQuaternion( obj.quaternion );

            obj.position.sub( delta );

        }

        for ( i = 0; i < node.nodes.length; i ++ ) {

            obj.add( createSceneGraph( node.nodes[i], node ) );

        }

        return obj;

    }

    function getJointId( skin, id ) {

        for ( var i = 0; i < skin.joints.length; i ++ ) {

            if ( skin.joints[ i ] === id ) {

                return i;

            }

        }

    }

    function getLibraryNode( id ) {

        var nodes = COLLADA.querySelectorAll('library_nodes node');

        for ( var i = 0; i < nodes.length; i++ ) {

            var attObj = nodes[i].attributes.getNamedItem('id');

            if ( attObj && attObj.value === id ) {

                return nodes[i];

            }

        }

        return undefined;

    }

    function getChannelsForNode ( node ) {

        var channels = [];
        var startTime = 1000000;
        var endTime = -1000000;

        for ( var id in animations ) {

            var animation = animations[id];

            for ( var i = 0; i < animation.channel.length; i ++ ) {

                var channel = animation.channel[i];
                var sampler = animation.sampler[i];
                var id = channel.target.split('/')[0];

                if ( id == node.id ) {

                    sampler.create();
                    channel.sampler = sampler;
                    startTime = Math.min(startTime, sampler.startTime);
                    endTime = Math.max(endTime, sampler.endTime);
                    channels.push(channel);

                }

            }

        }

        if ( channels.length ) {

            node.startTime = startTime;
            node.endTime = endTime;

        }

        return channels;

    }

    function calcFrameDuration( node ) {

        var minT = 10000000;

        for ( var i = 0; i < node.channels.length; i ++ ) {

            var sampler = node.channels[i].sampler;

            for ( var j = 0; j < sampler.input.length - 1; j ++ ) {

                var t0 = sampler.input[ j ];
                var t1 = sampler.input[ j + 1 ];
                minT = Math.min( minT, t1 - t0 );

            }
        }

        return minT;

    }

    function calcMatrixAt( node, t ) {

        var animated = {};

        var i, j;

        for ( i = 0; i < node.channels.length; i ++ ) {

            var channel = node.channels[ i ];
            animated[ channel.sid ] = channel;

        }

        var matrix = new THREE.Matrix4();

        for ( i = 0; i < node.transforms.length; i ++ ) {

            var transform = node.transforms[ i ];
            var channel = animated[ transform.sid ];

            if ( channel !== undefined ) {

                var sampler = channel.sampler;
                var value;

                for ( j = 0; j < sampler.input.length - 1; j ++ ) {

                    if ( sampler.input[ j + 1 ] > t ) {

                        value = sampler.output[ j ];
                        //console.log(value.flatten)
                        break;

                    }

                }

                if ( value !== undefined ) {

                    if ( value instanceof THREE.Matrix4 ) {

                        matrix.multiplyMatrices( matrix, value );

                    } else {

                        // FIXME: handle other types

                        matrix.multiplyMatrices( matrix, transform.matrix );

                    }

                } else {

                    matrix.multiplyMatrices( matrix, transform.matrix );

                }

            } else {

                matrix.multiplyMatrices( matrix, transform.matrix );

            }

        }

        return matrix;

    }

    function bakeAnimations ( node ) {

        if ( node.channels && node.channels.length ) {

            var keys = [],
                sids = [];

            for ( var i = 0, il = node.channels.length; i < il; i ++ ) {

                var channel = node.channels[i],
                    fullSid = channel.fullSid,
                    sampler = channel.sampler,
                    input = sampler.input,
                    transform = node.getTransformBySid( channel.sid ),
                    member;

                if ( channel.arrIndices ) {

                    member = [];

                    for ( var j = 0, jl = channel.arrIndices.length; j < jl; j ++ ) {

                        member[ j ] = getConvertedIndex( channel.arrIndices[ j ] );

                    }

                } else {

                    member = getConvertedMember( channel.member );

                }

                if ( transform ) {

                    if ( sids.indexOf( fullSid ) === -1 ) {

                        sids.push( fullSid );

                    }

                    for ( var j = 0, jl = input.length; j < jl; j ++ ) {

                        var time = input[j],
                            data = sampler.getData( transform.type, j, member ),
                            key = findKey( keys, time );

                        if ( !key ) {

                            key = new Key( time );
                            var timeNdx = findTimeNdx( keys, time );
                            keys.splice( timeNdx === -1 ? keys.length : timeNdx, 0, key );

                        }

                        key.addTarget( fullSid, transform, member, data );

                    }

                } else {

                    console.log( 'Could not find transform "' + channel.sid + '" in node ' + node.id );

                }

            }

            // post process
            for ( var i = 0; i < sids.length; i ++ ) {

                var sid = sids[ i ];

                for ( var j = 0; j < keys.length; j ++ ) {

                    var key = keys[ j ];

                    if ( !key.hasTarget( sid ) ) {

                        interpolateKeys( keys, key, j, sid );

                    }

                }

            }

            node.keys = keys;
            node.sids = sids;

        }

    }

    function findKey ( keys, time) {

        var retVal = null;

        for ( var i = 0, il = keys.length; i < il && retVal === null; i ++ ) {

            var key = keys[i];

            if ( key.time === time ) {

                retVal = key;

            } else if ( key.time > time ) {

                break;

            }

        }

        return retVal;

    }

    function findTimeNdx ( keys, time) {

        var ndx = -1;

        for ( var i = 0, il = keys.length; i < il && ndx === -1; i ++ ) {

            var key = keys[i];

            if ( key.time >= time ) {

                ndx = i;

            }

        }

        return ndx;

    }

    function interpolateKeys ( keys, key, ndx, fullSid ) {

        var prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx - 1 : 0 ),
            nextKey = getNextKeyWith( keys, fullSid, ndx + 1 );

        if ( prevKey && nextKey ) {

            var scale = (key.time - prevKey.time) / (nextKey.time - prevKey.time),
                prevTarget = prevKey.getTarget( fullSid ),
                nextData = nextKey.getTarget( fullSid ).data,
                prevData = prevTarget.data,
                data;

            if ( prevTarget.type === 'matrix' ) {

                data = prevData;

            } else if ( prevData.length ) {

                data = [];

                for ( var i = 0; i < prevData.length; ++ i ) {

                    data[ i ] = prevData[ i ] + ( nextData[ i ] - prevData[ i ] ) * scale;

                }

            } else {

                data = prevData + ( nextData - prevData ) * scale;

            }

            key.addTarget( fullSid, prevTarget.transform, prevTarget.member, data );

        }

    }

    // Get next key with given sid

    function getNextKeyWith( keys, fullSid, ndx ) {

        for ( ; ndx < keys.length; ndx ++ ) {

            var key = keys[ ndx ];

            if ( key.hasTarget( fullSid ) ) {

                return key;

            }

        }

        return null;

    }

    // Get previous key with given sid

    function getPrevKeyWith( keys, fullSid, ndx ) {

        ndx = ndx >= 0 ? ndx : ndx + keys.length;

        for ( ; ndx >= 0; ndx -- ) {

            var key = keys[ ndx ];

            if ( key.hasTarget( fullSid ) ) {

                return key;

            }

        }

        return null;

    }

    function _Image() {

        this.id = "";
        this.init_from = "";

    }

    _Image.prototype.parse = function(element) {

        this.id = element.getAttribute('id');

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            if ( child.nodeName === 'init_from' ) {

                this.init_from = child.textContent;

            }

        }

        return this;

    };

    function Controller() {

        this.id = "";
        this.name = "";
        this.type = "";
        this.skin = null;
        this.morph = null;

    }

    Controller.prototype.parse = function( element ) {

        this.id = element.getAttribute('id');
        this.name = element.getAttribute('name');
        this.type = "none";

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            switch ( child.nodeName ) {

                case 'skin':

                    this.skin = (new Skin()).parse(child);
                    this.type = child.nodeName;
                    break;

                case 'morph':

                    this.morph = (new Morph()).parse(child);
                    this.type = child.nodeName;
                    break;

                default:
                    break;

            }
        }

        return this;

    };

    function Morph() {

        this.method = null;
        this.source = null;
        this.targets = null;
        this.weights = null;

    }

    Morph.prototype.parse = function( element ) {

        var sources = {};
        var inputs = [];
        var i;

        this.method = element.getAttribute( 'method' );
        this.source = element.getAttribute( 'source' ).replace( /^#/, '' );

        for ( i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'source':

                    var source = ( new Source() ).parse( child );
                    sources[ source.id ] = source;
                    break;

                case 'targets':

                    inputs = this.parseInputs( child );
                    break;

                default:

                    console.log( child.nodeName );
                    break;

            }

        }

        for ( i = 0; i < inputs.length; i ++ ) {

            var input = inputs[ i ];
            var source = sources[ input.source ];

            switch ( input.semantic ) {

                case 'MORPH_TARGET':

                    this.targets = source.read();
                    break;

                case 'MORPH_WEIGHT':

                    this.weights = source.read();
                    break;

                default:
                    break;

            }
        }

        return this;

    };

    Morph.prototype.parseInputs = function(element) {

        var inputs = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1) continue;

            switch ( child.nodeName ) {

                case 'input':

                    inputs.push( (new Input()).parse(child) );
                    break;

                default:
                    break;
            }
        }

        return inputs;

    };

    function Skin() {

        this.source = "";
        this.bindShapeMatrix = null;
        this.invBindMatrices = [];
        this.joints = [];
        this.weights = [];

    }

    Skin.prototype.parse = function( element ) {

        var sources = {};
        var joints, weights;

        this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
        this.invBindMatrices = [];
        this.joints = [];
        this.weights = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'bind_shape_matrix':

                    var f = _floats(child.textContent);
                    this.bindShapeMatrix = getConvertedMat4( f );
                    break;

                case 'source':

                    var src = new Source().parse(child);
                    sources[ src.id ] = src;
                    break;

                case 'joints':

                    joints = child;
                    break;

                case 'vertex_weights':

                    weights = child;
                    break;

                default:

                    console.log( child.nodeName );
                    break;

            }
        }

        this.parseJoints( joints, sources );
        this.parseWeights( weights, sources );

        return this;

    };

    Skin.prototype.parseJoints = function ( element, sources ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'input':

                    var input = ( new Input() ).parse( child );
                    var source = sources[ input.source ];

                    if ( input.semantic === 'JOINT' ) {

                        this.joints = source.read();

                    } else if ( input.semantic === 'INV_BIND_MATRIX' ) {

                        this.invBindMatrices = source.read();

                    }

                    break;

                default:
                    break;
            }

        }

    };

    Skin.prototype.parseWeights = function ( element, sources ) {

        var v, vcount, inputs = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'input':

                    inputs.push( ( new Input() ).parse( child ) );
                    break;

                case 'v':

                    v = _ints( child.textContent );
                    break;

                case 'vcount':

                    vcount = _ints( child.textContent );
                    break;

                default:
                    break;

            }

        }

        var index = 0;

        for ( var i = 0; i < vcount.length; i ++ ) {

            var numBones = vcount[i];
            var vertex_weights = [];

            for ( var j = 0; j < numBones; j ++ ) {

                var influence = {};

                for ( var k = 0; k < inputs.length; k ++ ) {

                    var input = inputs[ k ];
                    var value = v[ index + input.offset ];

                    switch ( input.semantic ) {

                        case 'JOINT':

                            influence.joint = value;//this.joints[value];
                            break;

                        case 'WEIGHT':

                            influence.weight = sources[ input.source ].data[ value ];
                            break;

                        default:
                            break;

                    }

                }

                vertex_weights.push( influence );
                index += inputs.length;
            }

            for ( var j = 0; j < vertex_weights.length; j ++ ) {

                vertex_weights[ j ].index = i;

            }

            this.weights.push( vertex_weights );

        }

    };

    function VisualScene () {

        this.id = "";
        this.name = "";
        this.nodes = [];
        this.scene = new THREE.Group();

    }

    VisualScene.prototype.getChildById = function( id, recursive ) {

        for ( var i = 0; i < this.nodes.length; i ++ ) {

            var node = this.nodes[ i ].getChildById( id, recursive );

            if ( node ) {

                return node;

            }

        }

        return null;

    };

    VisualScene.prototype.getChildBySid = function( sid, recursive ) {

        for ( var i = 0; i < this.nodes.length; i ++ ) {

            var node = this.nodes[ i ].getChildBySid( sid, recursive );

            if ( node ) {

                return node;

            }

        }

        return null;

    };

    VisualScene.prototype.parse = function( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );
        this.nodes = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'node':

                    this.nodes.push( ( new Node() ).parse( child ) );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    function Node() {

        this.id = "";
        this.name = "";
        this.sid = "";
        this.nodes = [];
        this.controllers = [];
        this.transforms = [];
        this.geometries = [];
        this.channels = [];
        this.matrix = new THREE.Matrix4();

    }

    Node.prototype.getChannelForTransform = function( transformSid ) {

        for ( var i = 0; i < this.channels.length; i ++ ) {

            var channel = this.channels[i];
            var parts = channel.target.split('/');
            var id = parts.shift();
            var sid = parts.shift();
            var dotSyntax = (sid.indexOf(".") >= 0);
            var arrSyntax = (sid.indexOf("(") >= 0);
            var arrIndices;
            var member;

            if ( dotSyntax ) {

                parts = sid.split(".");
                sid = parts.shift();
                member = parts.shift();

            } else if ( arrSyntax ) {

                arrIndices = sid.split("(");
                sid = arrIndices.shift();

                for ( var j = 0; j < arrIndices.length; j ++ ) {

                    arrIndices[ j ] = parseInt( arrIndices[ j ].replace( /\)/, '' ) );

                }

            }

            if ( sid === transformSid ) {

                channel.info = { sid: sid, dotSyntax: dotSyntax, arrSyntax: arrSyntax, arrIndices: arrIndices };
                return channel;

            }

        }

        return null;

    };

    Node.prototype.getChildById = function ( id, recursive ) {

        if ( this.id === id ) {

            return this;

        }

        if ( recursive ) {

            for ( var i = 0; i < this.nodes.length; i ++ ) {

                var n = this.nodes[ i ].getChildById( id, recursive );

                if ( n ) {

                    return n;

                }

            }

        }

        return null;

    };

    Node.prototype.getChildBySid = function ( sid, recursive ) {

        if ( this.sid === sid ) {

            return this;

        }

        if ( recursive ) {

            for ( var i = 0; i < this.nodes.length; i ++ ) {

                var n = this.nodes[ i ].getChildBySid( sid, recursive );

                if ( n ) {

                    return n;

                }

            }
        }

        return null;

    };

    Node.prototype.getTransformBySid = function ( sid ) {

        for ( var i = 0; i < this.transforms.length; i ++ ) {

            if ( this.transforms[ i ].sid === sid ) return this.transforms[ i ];

        }

        return null;

    };

    Node.prototype.parse = function( element ) {

        var url;

        this.id = element.getAttribute('id');
        this.sid = element.getAttribute('sid');
        this.name = element.getAttribute('name');
        this.type = element.getAttribute('type');
        this.layer = element.getAttribute('layer');

        this.type = this.type === 'JOINT' ? this.type : 'NODE';

        this.nodes = [];
        this.transforms = [];
        this.geometries = [];
        this.cameras = [];
        this.lights = [];
        this.controllers = [];
        this.matrix = new THREE.Matrix4();

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'node':

                    this.nodes.push( ( new Node() ).parse( child ) );
                    break;

                case 'instance_camera':

                    this.cameras.push( ( new InstanceCamera() ).parse( child ) );
                    break;

                case 'instance_controller':

                    this.controllers.push( ( new InstanceController() ).parse( child ) );
                    break;

                case 'instance_geometry':

                    this.geometries.push( ( new InstanceGeometry() ).parse( child ) );
                    break;

                case 'instance_light':

                    this.lights.push( ( new InstanceLight() ).parse( child ) );
                    break;

                case 'instance_node':

                    url = child.getAttribute( 'url' ).replace( /^#/, '' );
                    var iNode = getLibraryNode( url );

                    if ( iNode ) {

                        this.nodes.push( ( new Node() ).parse( iNode )) ;

                    }

                    break;

                case 'rotate':
                case 'translate':
                case 'scale':
                case 'matrix':
                case 'lookat':
                case 'skew':

                    this.transforms.push( ( new Transform() ).parse( child ) );
                    break;

                case 'extra':
                    break;

                default:

                    console.log( child.nodeName );
                    break;

            }

        }

        this.channels = getChannelsForNode( this );
        bakeAnimations( this );

        this.updateMatrix();

        return this;

    };

    Node.prototype.updateMatrix = function () {

        this.matrix.identity();

        for ( var i = 0; i < this.transforms.length; i ++ ) {

            this.transforms[ i ].apply( this.matrix );

        }

    };

    function Transform () {

        this.sid = "";
        this.type = "";
        this.data = [];
        this.obj = null;

    }

    Transform.prototype.parse = function ( element ) {

        this.sid = element.getAttribute( 'sid' );
        this.type = element.nodeName;
        this.data = _floats( element.textContent );
        this.convert();

        return this;

    };

    Transform.prototype.convert = function () {

        switch ( this.type ) {

            case 'matrix':

                this.obj = getConvertedMat4( this.data );
                break;

            case 'rotate':

                this.angle = THREE.Math.degToRad( this.data[3] );

            case 'translate':

                fixCoords( this.data, -1 );
                this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
                break;

            case 'scale':

                fixCoords( this.data, 1 );
                this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
                break;

            default:
                console.log( 'Can not convert Transform of type ' + this.type );
                break;

        }

    };

    Transform.prototype.apply = function () {

        var m1 = new THREE.Matrix4();

        return function ( matrix ) {

            switch ( this.type ) {

                case 'matrix':

                    matrix.multiply( this.obj );

                    break;

                case 'translate':

                    matrix.multiply( m1.makeTranslation( this.obj.x, this.obj.y, this.obj.z ) );

                    break;

                case 'rotate':

                    matrix.multiply( m1.makeRotationAxis( this.obj, this.angle ) );

                    break;

                case 'scale':

                    matrix.scale( this.obj );

                    break;

            }

        };

    }();

    Transform.prototype.update = function ( data, member ) {

        var members = [ 'X', 'Y', 'Z', 'ANGLE' ];

        switch ( this.type ) {

            case 'matrix':

                if ( ! member ) {

                    this.obj.copy( data );

                } else if ( member.length === 1 ) {

                    switch ( member[ 0 ] ) {

                        case 0:

                            this.obj.n11 = data[ 0 ];
                            this.obj.n21 = data[ 1 ];
                            this.obj.n31 = data[ 2 ];
                            this.obj.n41 = data[ 3 ];

                            break;

                        case 1:

                            this.obj.n12 = data[ 0 ];
                            this.obj.n22 = data[ 1 ];
                            this.obj.n32 = data[ 2 ];
                            this.obj.n42 = data[ 3 ];

                            break;

                        case 2:

                            this.obj.n13 = data[ 0 ];
                            this.obj.n23 = data[ 1 ];
                            this.obj.n33 = data[ 2 ];
                            this.obj.n43 = data[ 3 ];

                            break;

                        case 3:

                            this.obj.n14 = data[ 0 ];
                            this.obj.n24 = data[ 1 ];
                            this.obj.n34 = data[ 2 ];
                            this.obj.n44 = data[ 3 ];

                            break;

                    }

                } else if ( member.length === 2 ) {

                    var propName = 'n' + ( member[ 0 ] + 1 ) + ( member[ 1 ] + 1 );
                    this.obj[ propName ] = data;

                } else {

                    console.log('Incorrect addressing of matrix in transform.');

                }

                break;

            case 'translate':
            case 'scale':

                if ( Object.prototype.toString.call( member ) === '[object Array]' ) {

                    member = members[ member[ 0 ] ];

                }

                switch ( member ) {

                    case 'X':

                        this.obj.x = data;
                        break;

                    case 'Y':

                        this.obj.y = data;
                        break;

                    case 'Z':

                        this.obj.z = data;
                        break;

                    default:

                        this.obj.x = data[ 0 ];
                        this.obj.y = data[ 1 ];
                        this.obj.z = data[ 2 ];
                        break;

                }

                break;

            case 'rotate':

                if ( Object.prototype.toString.call( member ) === '[object Array]' ) {

                    member = members[ member[ 0 ] ];

                }

                switch ( member ) {

                    case 'X':

                        this.obj.x = data;
                        break;

                    case 'Y':

                        this.obj.y = data;
                        break;

                    case 'Z':

                        this.obj.z = data;
                        break;

                    case 'ANGLE':

                        this.angle = THREE.Math.degToRad( data );
                        break;

                    default:

                        this.obj.x = data[ 0 ];
                        this.obj.y = data[ 1 ];
                        this.obj.z = data[ 2 ];
                        this.angle = THREE.Math.degToRad( data[ 3 ] );
                        break;

                }
                break;

        }

    };

    function InstanceController() {

        this.url = "";
        this.skeleton = [];
        this.instance_material = [];

    }

    InstanceController.prototype.parse = function ( element ) {

        this.url = element.getAttribute('url').replace(/^#/, '');
        this.skeleton = [];
        this.instance_material = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType !== 1 ) continue;

            switch ( child.nodeName ) {

                case 'skeleton':

                    this.skeleton.push( child.textContent.replace(/^#/, '') );
                    break;

                case 'bind_material':

                    var instances = child.querySelectorAll('instance_material');

                    for ( var j = 0; j < instances.length; j ++ ) {

                        var instance = instances[j];
                        this.instance_material.push( (new InstanceMaterial()).parse(instance) );

                    }


                    break;

                case 'extra':
                    break;

                default:
                    break;

            }
        }

        return this;

    };

    function InstanceMaterial () {

        this.symbol = "";
        this.target = "";

    }

    InstanceMaterial.prototype.parse = function ( element ) {

        this.symbol = element.getAttribute('symbol');
        this.target = element.getAttribute('target').replace(/^#/, '');
        return this;

    };

    function InstanceGeometry() {

        this.url = "";
        this.instance_material = [];

    }

    InstanceGeometry.prototype.parse = function ( element ) {

        this.url = element.getAttribute('url').replace(/^#/, '');
        this.instance_material = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1 ) continue;

            if ( child.nodeName === 'bind_material' ) {

                var instances = child.querySelectorAll('instance_material');

                for ( var j = 0; j < instances.length; j ++ ) {

                    var instance = instances[j];
                    this.instance_material.push( (new InstanceMaterial()).parse(instance) );

                }

                break;

            }

        }

        return this;

    };

    function Geometry() {

        this.id = "";
        this.mesh = null;

    }

    Geometry.prototype.parse = function ( element ) {

        this.id = element.getAttribute('id');

        extractDoubleSided( this, element );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];

            switch ( child.nodeName ) {

                case 'mesh':

                    this.mesh = (new Mesh(this)).parse(child);
                    break;

                case 'extra':

                    // console.log( child );
                    break;

                default:
                    break;
            }
        }

        return this;

    };

    function Mesh( geometry ) {

        this.geometry = geometry.id;
        this.primitives = [];
        this.vertices = null;
        this.geometry3js = null;

    }

    Mesh.prototype.parse = function ( element ) {

        this.primitives = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            switch ( child.nodeName ) {

                case 'source':

                    _source( child );
                    break;

                case 'vertices':

                    this.vertices = ( new Vertices() ).parse( child );
                    break;

                case 'linestrips':

                    this.primitives.push( ( new LineStrips().parse( child ) ) );
                    break;

                case 'triangles':

                    this.primitives.push( ( new Triangles().parse( child ) ) );
                    break;

                case 'polygons':

                    this.primitives.push( ( new Polygons().parse( child ) ) );
                    break;

                case 'polylist':

                    this.primitives.push( ( new Polylist().parse( child ) ) );
                    break;

                default:
                    break;

            }

        }

        this.geometry3js = new THREE.Geometry();

        if ( this.vertices === null ) {

            // TODO (mrdoob): Study case when this is null (carrier.dae)

            return this;

        }

        var vertexData = sources[ this.vertices.input['POSITION'].source ].data;

        for ( var i = 0; i < vertexData.length; i += 3 ) {

            this.geometry3js.vertices.push( getConvertedVec3( vertexData, i ).clone() );

        }

        for ( var i = 0; i < this.primitives.length; i ++ ) {

            var primitive = this.primitives[ i ];
            primitive.setVertices( this.vertices );
            this.handlePrimitive( primitive, this.geometry3js );

        }

        if ( this.geometry3js.calcNormals ) {

            this.geometry3js.computeVertexNormals();
            delete this.geometry3js.calcNormals;

        }

        return this;

    };

    Mesh.prototype.handlePrimitive = function ( primitive, geom ) {

        if ( primitive instanceof LineStrips ) {

            // TODO: Handle indices. Maybe easier with BufferGeometry?

            geom.isLineStrip = true;
            return;

        }

        var j, k, pList = primitive.p, inputs = primitive.inputs;
        var input, index, idx32;
        var source, numParams;
        var vcIndex = 0, vcount = 3, maxOffset = 0;
        var texture_sets = [];

        for ( j = 0; j < inputs.length; j ++ ) {

            input = inputs[ j ];

            var offset = input.offset + 1;
            maxOffset = (maxOffset < offset) ? offset : maxOffset;

            switch ( input.semantic ) {

                case 'TEXCOORD':
                    texture_sets.push( input.set );
                    break;

            }

        }

        for ( var pCount = 0; pCount < pList.length; ++ pCount ) {

            var p = pList[ pCount ], i = 0;

            while ( i < p.length ) {

                var vs = [];
                var ns = [];
                var ts = null;
                var cs = [];

                if ( primitive.vcount ) {

                    vcount = primitive.vcount.length ? primitive.vcount[ vcIndex ++ ] : primitive.vcount;

                } else {

                    vcount = p.length / maxOffset;

                }


                for ( j = 0; j < vcount; j ++ ) {

                    for ( k = 0; k < inputs.length; k ++ ) {

                        input = inputs[ k ];
                        source = sources[ input.source ];

                        index = p[ i + ( j * maxOffset ) + input.offset ];
                        numParams = source.accessor.params.length;
                        idx32 = index * numParams;

                        switch ( input.semantic ) {

                            case 'VERTEX':

                                vs.push( index );

                                break;

                            case 'NORMAL':

                                ns.push( getConvertedVec3( source.data, idx32 ) );

                                break;

                            case 'TEXCOORD':

                                ts = ts || { };
                                if ( ts[ input.set ] === undefined ) ts[ input.set ] = [];
                                // invert the V
                                ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], source.data[ idx32 + 1 ] ) );

                                break;

                            case 'COLOR':

                                cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );

                                break;

                            default:

                                break;

                        }

                    }

                }

                if ( ns.length === 0 ) {

                    // check the vertices inputs
                    input = this.vertices.input.NORMAL;

                    if ( input ) {

                        source = sources[ input.source ];
                        numParams = source.accessor.params.length;

                        for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {

                            ns.push( getConvertedVec3( source.data, vs[ ndx ] * numParams ) );

                        }

                    } else {

                        geom.calcNormals = true;

                    }

                }

                if ( !ts ) {

                    ts = { };
                    // check the vertices inputs
                    input = this.vertices.input.TEXCOORD;

                    if ( input ) {

                        texture_sets.push( input.set );
                        source = sources[ input.source ];
                        numParams = source.accessor.params.length;

                        for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {

                            idx32 = vs[ ndx ] * numParams;
                            if ( ts[ input.set ] === undefined ) ts[ input.set ] = [ ];
                            // invert the V
                            ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], 1.0 - source.data[ idx32 + 1 ] ) );

                        }

                    }

                }

                if ( cs.length === 0 ) {

                    // check the vertices inputs
                    input = this.vertices.input.COLOR;

                    if ( input ) {

                        source = sources[ input.source ];
                        numParams = source.accessor.params.length;

                        for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {

                            idx32 = vs[ ndx ] * numParams;
                            cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );

                        }

                    }

                }

                var face = null, faces = [], uv, uvArr;

                if ( vcount === 3 ) {

                    faces.push( new THREE.Face3( vs[0], vs[1], vs[2], ns, cs.length ? cs : new THREE.Color() ) );

                } else if ( vcount === 4 ) {

                    faces.push( new THREE.Face3( vs[0], vs[1], vs[3], ns.length ? [ ns[0].clone(), ns[1].clone(), ns[3].clone() ] : [], cs.length ? [ cs[0], cs[1], cs[3] ] : new THREE.Color() ) );

                    faces.push( new THREE.Face3( vs[1], vs[2], vs[3], ns.length ? [ ns[1].clone(), ns[2].clone(), ns[3].clone() ] : [], cs.length ? [ cs[1], cs[2], cs[3] ] : new THREE.Color() ) );

                } else if ( vcount > 4 && options.subdivideFaces ) {

                    var clr = cs.length ? cs : new THREE.Color(),
                        vec1, vec2, vec3, v1, v2, norm;

                    // subdivide into multiple Face3s

                    for ( k = 1; k < vcount - 1; ) {

                        faces.push( new THREE.Face3( vs[0], vs[k], vs[k + 1], ns.length ? [ ns[0].clone(), ns[k ++].clone(), ns[k].clone() ] : [], clr ) );

                    }

                }

                if ( faces.length ) {

                    for ( var ndx = 0, len = faces.length; ndx < len; ndx ++ ) {

                        face = faces[ndx];
                        face.daeMaterial = primitive.material;
                        geom.faces.push( face );

                        for ( k = 0; k < texture_sets.length; k ++ ) {

                            uv = ts[ texture_sets[k] ];

                            if ( vcount > 4 ) {

                                // Grab the right UVs for the vertices in this face
                                uvArr = [ uv[0], uv[ndx + 1], uv[ndx + 2] ];

                            } else if ( vcount === 4 ) {

                                if ( ndx === 0 ) {

                                    uvArr = [ uv[0], uv[1], uv[3] ];

                                } else {

                                    uvArr = [ uv[1].clone(), uv[2], uv[3].clone() ];

                                }

                            } else {

                                uvArr = [ uv[0], uv[1], uv[2] ];

                            }

                            if ( geom.faceVertexUvs[k] === undefined ) {

                                geom.faceVertexUvs[k] = [];

                            }

                            geom.faceVertexUvs[k].push( uvArr );

                        }

                    }

                } else {

                    console.log( 'dropped face with vcount ' + vcount + ' for geometry with id: ' + geom.id );

                }

                i += maxOffset * vcount;

            }

        }

    };

    function Polygons () {

        this.material = "";
        this.count = 0;
        this.inputs = [];
        this.vcount = null;
        this.p = [];
        this.geometry = new THREE.Geometry();

    }

    Polygons.prototype.setVertices = function ( vertices ) {

        for ( var i = 0; i < this.inputs.length; i ++ ) {

            if ( this.inputs[ i ].source === vertices.id ) {

                this.inputs[ i ].source = vertices.input[ 'POSITION' ].source;

            }

        }

    };

    Polygons.prototype.parse = function ( element ) {

        this.material = element.getAttribute( 'material' );
        this.count = _attr_as_int( element, 'count', 0 );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            switch ( child.nodeName ) {

                case 'input':

                    this.inputs.push( ( new Input() ).parse( element.childNodes[ i ] ) );
                    break;

                case 'vcount':

                    this.vcount = _ints( child.textContent );
                    break;

                case 'p':

                    this.p.push( _ints( child.textContent ) );
                    break;

                case 'ph':

                    console.warn( 'polygon holes not yet supported!' );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    function Polylist () {

        Polygons.call( this );

        this.vcount = [];

    }

    Polylist.prototype = Object.create( Polygons.prototype );
    Polylist.prototype.constructor = Polylist;

    function LineStrips() {

        Polygons.call( this );

        this.vcount = 1;

    }

    LineStrips.prototype = Object.create( Polygons.prototype );
    LineStrips.prototype.constructor = LineStrips;

    function Triangles () {

        Polygons.call( this );

        this.vcount = 3;

    }

    Triangles.prototype = Object.create( Polygons.prototype );
    Triangles.prototype.constructor = Triangles;

    function Accessor() {

        this.source = "";
        this.count = 0;
        this.stride = 0;
        this.params = [];

    }

    Accessor.prototype.parse = function ( element ) {

        this.params = [];
        this.source = element.getAttribute( 'source' );
        this.count = _attr_as_int( element, 'count', 0 );
        this.stride = _attr_as_int( element, 'stride', 0 );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            if ( child.nodeName === 'param' ) {

                var param = {};
                param[ 'name' ] = child.getAttribute( 'name' );
                param[ 'type' ] = child.getAttribute( 'type' );
                this.params.push( param );

            }

        }

        return this;

    };

    function Vertices() {

        this.input = {};

    }

    Vertices.prototype.parse = function ( element ) {

        this.id = element.getAttribute('id');

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            if ( element.childNodes[i].nodeName === 'input' ) {

                var input = ( new Input() ).parse( element.childNodes[ i ] );
                this.input[ input.semantic ] = input;

            }

        }

        return this;

    };

    function Input () {

        this.semantic = "";
        this.offset = 0;
        this.source = "";
        this.set = 0;

    }

    Input.prototype.parse = function ( element ) {

        this.semantic = element.getAttribute('semantic');
        this.source = element.getAttribute('source').replace(/^#/, '');
        this.set = _attr_as_int(element, 'set', -1);
        this.offset = _attr_as_int(element, 'offset', 0);

        if ( this.semantic === 'TEXCOORD' && this.set < 0 ) {

            this.set = 0;

        }

        return this;

    };

    function Source ( id ) {

        this.id = id;
        this.type = null;

    }

    Source.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];

            switch ( child.nodeName ) {

                case 'bool_array':

                    this.data = _bools( child.textContent );
                    this.type = child.nodeName;
                    break;

                case 'float_array':

                    this.data = _floats( child.textContent );
                    this.type = child.nodeName;
                    break;

                case 'int_array':

                    this.data = _ints( child.textContent );
                    this.type = child.nodeName;
                    break;

                case 'IDREF_array':
                case 'Name_array':

                    this.data = _strings( child.textContent );
                    this.type = child.nodeName;
                    break;

                case 'technique_common':

                    for ( var j = 0; j < child.childNodes.length; j ++ ) {

                        if ( child.childNodes[ j ].nodeName === 'accessor' ) {

                            this.accessor = ( new Accessor() ).parse( child.childNodes[ j ] );
                            break;

                        }
                    }
                    break;

                default:
                    // console.log(child.nodeName);
                    break;

            }

        }

        return this;

    };

    Source.prototype.read = function () {

        var result = [];

        //for (var i = 0; i < this.accessor.params.length; i++) {

        var param = this.accessor.params[ 0 ];

            //console.log(param.name + " " + param.type);

        switch ( param.type ) {

            case 'IDREF':
            case 'Name': case 'name':
            case 'float':

                return this.data;

            case 'float4x4':

                for ( var j = 0; j < this.data.length; j += 16 ) {

                    var s = this.data.slice( j, j + 16 );
                    var m = getConvertedMat4( s );
                    result.push( m );
                }

                break;

            default:

                console.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' );
                break;

        }

        //}

        return result;

    };

    function Material () {

        this.id = "";
        this.name = "";
        this.instance_effect = null;

    }

    Material.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            if ( element.childNodes[ i ].nodeName === 'instance_effect' ) {

                this.instance_effect = ( new InstanceEffect() ).parse( element.childNodes[ i ] );
                break;

            }

        }

        return this;

    };

    function ColorOrTexture () {

        this.color = new THREE.Color();
        this.color.setRGB( Math.random(), Math.random(), Math.random() );
        this.color.a = 1.0;

        this.texture = null;
        this.texcoord = null;
        this.texOpts = null;

    }

    ColorOrTexture.prototype.isColor = function () {

        return ( this.texture === null );

    };

    ColorOrTexture.prototype.isTexture = function () {

        return ( this.texture != null );

    };

    ColorOrTexture.prototype.parse = function ( element ) {

        if (element.nodeName === 'transparent') {

            this.opaque = element.getAttribute('opaque');

        }

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'color':

                    var rgba = _floats( child.textContent );
                    this.color = new THREE.Color();
                    this.color.setRGB( rgba[0], rgba[1], rgba[2] );
                    this.color.a = rgba[3];
                    break;

                case 'texture':

                    this.texture = child.getAttribute('texture');
                    this.texcoord = child.getAttribute('texcoord');
                    // Defaults from:
                    // https://collada.org/mediawiki/index.php/Maya_texture_placement_MAYA_extension
                    this.texOpts = {
                        offsetU: 0,
                        offsetV: 0,
                        repeatU: 1,
                        repeatV: 1,
                        wrapU: 1,
                        wrapV: 1
                    };
                    this.parseTexture( child );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    ColorOrTexture.prototype.parseTexture = function ( element ) {

        if ( ! element.childNodes ) return this;

        // This should be supported by Maya, 3dsMax, and MotionBuilder

        if ( element.childNodes[1] && element.childNodes[1].nodeName === 'extra' ) {

            element = element.childNodes[1];

            if ( element.childNodes[1] && element.childNodes[1].nodeName === 'technique' ) {

                element = element.childNodes[1];

            }

        }

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            switch ( child.nodeName ) {

                case 'offsetU':
                case 'offsetV':
                case 'repeatU':
                case 'repeatV':

                    this.texOpts[ child.nodeName ] = parseFloat( child.textContent );

                    break;

                case 'wrapU':
                case 'wrapV':

                    // some dae have a value of true which becomes NaN via parseInt

                    if ( child.textContent.toUpperCase() === 'TRUE' ) {

                        this.texOpts[ child.nodeName ] = 1;

                    } else {

                        this.texOpts[ child.nodeName ] = parseInt( child.textContent );

                    }
                    break;

                default:

                    this.texOpts[ child.nodeName ] = child.textContent;

                    break;

            }

        }

        return this;

    };

    function Shader ( type, effect ) {

        this.type = type;
        this.effect = effect;
        this.material = null;

    }

    Shader.prototype.parse = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'emission':
                case 'diffuse':
                case 'specular':
                case 'transparent':

                    this[ child.nodeName ] = ( new ColorOrTexture() ).parse( child );
                    break;

                case 'bump':

                    // If 'bumptype' is 'heightfield', create a 'bump' property
                    // Else if 'bumptype' is 'normalmap', create a 'normal' property
                    // (Default to 'bump')
                    var bumpType = child.getAttribute( 'bumptype' );
                    if ( bumpType ) {
                        if ( bumpType.toLowerCase() === "heightfield" ) {
                            this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
                        } else if ( bumpType.toLowerCase() === "normalmap" ) {
                            this[ 'normal' ] = ( new ColorOrTexture() ).parse( child );
                        } else {
                            console.error( "Shader.prototype.parse: Invalid value for attribute 'bumptype' (" + bumpType + ") - valid bumptypes are 'HEIGHTFIELD' and 'NORMALMAP' - defaulting to 'HEIGHTFIELD'" );
                            this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
                        }
                    } else {
                        console.warn( "Shader.prototype.parse: Attribute 'bumptype' missing from bump node - defaulting to 'HEIGHTFIELD'" );
                        this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
                    }

                    break;

                case 'shininess':
                case 'reflectivity':
                case 'index_of_refraction':
                case 'transparency':

                    var f = child.querySelectorAll('float');

                    if ( f.length > 0 )
                        this[ child.nodeName ] = parseFloat( f[ 0 ].textContent );

                    break;

                default:
                    break;

            }

        }

        this.create();
        return this;

    };

    Shader.prototype.create = function() {

        var props = {};

        var transparent = false;

        if (this['transparency'] !== undefined && this['transparent'] !== undefined) {
            // convert transparent color RBG to average value
            var transparentColor = this['transparent'];
            var transparencyLevel = (this.transparent.color.r + this.transparent.color.g + this.transparent.color.b) / 3 * this.transparency;

            if (transparencyLevel > 0) {
                transparent = true;
                props[ 'transparent' ] = true;
                props[ 'opacity' ] = 1 - transparencyLevel;

            }

        }

        var keys = {
            'diffuse':'map',
            'ambient':'lightMap',
            'specular':'specularMap',
            'emission':'emissionMap',
            'bump':'bumpMap',
            'normal':'normalMap'
            };

        for ( var prop in this ) {

            switch ( prop ) {

                case 'ambient':
                case 'emission':
                case 'diffuse':
                case 'specular':
                case 'bump':
                case 'normal':

                    var cot = this[ prop ];

                    if ( cot instanceof ColorOrTexture ) {

                        if ( cot.isTexture() ) {

                            var samplerId = cot.texture;
                            var surfaceId = this.effect.sampler[samplerId];

                            if ( surfaceId !== undefined && surfaceId.source !== undefined ) {

                                var surface = this.effect.surface[surfaceId.source];

                                if ( surface !== undefined ) {

                                    var image = images[ surface.init_from ];

                                    if ( image ) {

                                        var url = baseUrl + image.init_from;

                                        var texture;
                                        var loader = THREE.Loader.Handlers.get( url );

                                        if ( loader !== null ) {

                                            texture = loader.load( url );

                                        } else {

                                            texture = new THREE.Texture();

                                            loadTextureImage( texture, url );

                                        }

                                        texture.wrapS = cot.texOpts.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
                                        texture.wrapT = cot.texOpts.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
                                        texture.offset.x = cot.texOpts.offsetU;
                                        texture.offset.y = cot.texOpts.offsetV;
                                        texture.repeat.x = cot.texOpts.repeatU;
                                        texture.repeat.y = cot.texOpts.repeatV;
                                        props[keys[prop]] = texture;

                                        // Texture with baked lighting?
                                        if (prop === 'emission') props['emissive'] = 0xffffff;

                                    }

                                }

                            }

                        } else if ( prop === 'diffuse' || !transparent ) {

                            if ( prop === 'emission' ) {

                                props[ 'emissive' ] = cot.color.getHex();

                            } else {

                                props[ prop ] = cot.color.getHex();

                            }

                        }

                    }

                    break;

                case 'shininess':

                    props[ prop ] = this[ prop ];
                    break;

                case 'reflectivity':

                    props[ prop ] = this[ prop ];
                    if ( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap;
                    props['combine'] = THREE.MixOperation;    //mix regular shading with reflective component
                    break;

                case 'index_of_refraction':

                    props[ 'refractionRatio' ] = this[ prop ]; //TODO: "index_of_refraction" becomes "refractionRatio" in shader, but I'm not sure if the two are actually comparable
                    if ( this[ prop ] !== 1.0 ) props['envMap'] = options.defaultEnvMap;
                    break;

                case 'transparency':
                    // gets figured out up top
                    break;

                default:
                    break;

            }

        }

        props[ 'shading' ] = preferredShading;
        props[ 'side' ] = this.effect.doubleSided ? THREE.DoubleSide : THREE.FrontSide;

        if ( props.diffuse !== undefined ) {

            props.color = props.diffuse;
            delete props.diffuse;

        }

        switch ( this.type ) {

            case 'constant':

                if (props.emissive != undefined) props.color = props.emissive;
                this.material = new THREE.MeshBasicMaterial( props );
                break;

            case 'phong':
            case 'blinn':

                this.material = new THREE.MeshPhongMaterial( props );
                break;

            case 'lambert':
            default:

                this.material = new THREE.MeshLambertMaterial( props );
                break;

        }

        return this.material;

    };

    function Surface ( effect ) {

        this.effect = effect;
        this.init_from = null;
        this.format = null;

    }

    Surface.prototype.parse = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'init_from':

                    this.init_from = child.textContent;
                    break;

                case 'format':

                    this.format = child.textContent;
                    break;

                default:

                    console.log( "unhandled Surface prop: " + child.nodeName );
                    break;

            }

        }

        return this;

    };

    function Sampler2D ( effect ) {

        this.effect = effect;
        this.source = null;
        this.wrap_s = null;
        this.wrap_t = null;
        this.minfilter = null;
        this.magfilter = null;
        this.mipfilter = null;

    }

    Sampler2D.prototype.parse = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'source':

                    this.source = child.textContent;
                    break;

                case 'minfilter':

                    this.minfilter = child.textContent;
                    break;

                case 'magfilter':

                    this.magfilter = child.textContent;
                    break;

                case 'mipfilter':

                    this.mipfilter = child.textContent;
                    break;

                case 'wrap_s':

                    this.wrap_s = child.textContent;
                    break;

                case 'wrap_t':

                    this.wrap_t = child.textContent;
                    break;

                default:

                    console.log( "unhandled Sampler2D prop: " + child.nodeName );
                    break;

            }

        }

        return this;

    };

    function Effect () {

        this.id = "";
        this.name = "";
        this.shader = null;
        this.surface = {};
        this.sampler = {};

    }

    Effect.prototype.create = function () {

        if ( this.shader === null ) {

            return null;

        }

    };

    Effect.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );

        extractDoubleSided( this, element );

        this.shader = null;

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'profile_COMMON':

                    this.parseTechnique( this.parseProfileCOMMON( child ) );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    Effect.prototype.parseNewparam = function ( element ) {

        var sid = element.getAttribute( 'sid' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'surface':

                    this.surface[sid] = ( new Surface( this ) ).parse( child );
                    break;

                case 'sampler2D':

                    this.sampler[sid] = ( new Sampler2D( this ) ).parse( child );
                    break;

                case 'extra':

                    break;

                default:

                    console.log( child.nodeName );
                    break;

            }

        }

    };

    Effect.prototype.parseProfileCOMMON = function ( element ) {

        var technique;

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'profile_COMMON':

                    this.parseProfileCOMMON( child );
                    break;

                case 'technique':

                    technique = child;
                    break;

                case 'newparam':

                    this.parseNewparam( child );
                    break;

                case 'image':

                    var _image = ( new _Image() ).parse( child );
                    images[ _image.id ] = _image;
                    break;

                case 'extra':
                    break;

                default:

                    console.log( child.nodeName );
                    break;

            }

        }

        return technique;

    };

    Effect.prototype.parseTechnique = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'constant':
                case 'lambert':
                case 'blinn':
                case 'phong':

                    this.shader = ( new Shader( child.nodeName, this ) ).parse( child );
                    break;
                case 'extra':
                    this.parseExtra(child);
                    break;
                default:
                    break;

            }

        }

    };

    Effect.prototype.parseExtra = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'technique':
                    this.parseExtraTechnique( child );
                    break;
                default:
                    break;

            }

        }

    };

    Effect.prototype.parseExtraTechnique = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[i];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'bump':
                    this.shader.parse( element );
                    break;
                default:
                    break;

            }

        }

    };

    function InstanceEffect () {

        this.url = "";

    }

    InstanceEffect.prototype.parse = function ( element ) {

        this.url = element.getAttribute( 'url' ).replace( /^#/, '' );
        return this;

    };

    function Animation() {

        this.id = "";
        this.name = "";
        this.source = {};
        this.sampler = [];
        this.channel = [];

    }

    Animation.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );
        this.source = {};

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'animation':

                    var anim = ( new Animation() ).parse( child );

                    for ( var src in anim.source ) {

                        this.source[ src ] = anim.source[ src ];

                    }

                    for ( var j = 0; j < anim.channel.length; j ++ ) {

                        this.channel.push( anim.channel[ j ] );
                        this.sampler.push( anim.sampler[ j ] );

                    }

                    break;

                case 'source':

                    var src = ( new Source() ).parse( child );
                    this.source[ src.id ] = src;
                    break;

                case 'sampler':

                    this.sampler.push( ( new Sampler( this ) ).parse( child ) );
                    break;

                case 'channel':

                    this.channel.push( ( new Channel( this ) ).parse( child ) );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    function Channel( animation ) {

        this.animation = animation;
        this.source = "";
        this.target = "";
        this.fullSid = null;
        this.sid = null;
        this.dotSyntax = null;
        this.arrSyntax = null;
        this.arrIndices = null;
        this.member = null;

    }

    Channel.prototype.parse = function ( element ) {

        this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
        this.target = element.getAttribute( 'target' );

        var parts = this.target.split( '/' );

        var id = parts.shift();
        var sid = parts.shift();

        var dotSyntax = ( sid.indexOf(".") >= 0 );
        var arrSyntax = ( sid.indexOf("(") >= 0 );

        if ( dotSyntax ) {

            parts = sid.split(".");
            this.sid = parts.shift();
            this.member = parts.shift();

        } else if ( arrSyntax ) {

            var arrIndices = sid.split("(");
            this.sid = arrIndices.shift();

            for (var j = 0; j < arrIndices.length; j ++ ) {

                arrIndices[j] = parseInt( arrIndices[j].replace(/\)/, '') );

            }

            this.arrIndices = arrIndices;

        } else {

            this.sid = sid;

        }

        this.fullSid = sid;
        this.dotSyntax = dotSyntax;
        this.arrSyntax = arrSyntax;

        return this;

    };

    function Sampler ( animation ) {

        this.id = "";
        this.animation = animation;
        this.inputs = [];
        this.input = null;
        this.output = null;
        this.strideOut = null;
        this.interpolation = null;
        this.startTime = null;
        this.endTime = null;
        this.duration = 0;

    }

    Sampler.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.inputs = [];

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'input':

                    this.inputs.push( (new Input()).parse( child ) );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    Sampler.prototype.create = function () {

        for ( var i = 0; i < this.inputs.length; i ++ ) {

            var input = this.inputs[ i ];
            var source = this.animation.source[ input.source ];

            switch ( input.semantic ) {

                case 'INPUT':

                    this.input = source.read();
                    break;

                case 'OUTPUT':

                    this.output = source.read();
                    this.strideOut = source.accessor.stride;
                    break;

                case 'INTERPOLATION':

                    this.interpolation = source.read();
                    break;

                case 'IN_TANGENT':

                    break;

                case 'OUT_TANGENT':

                    break;

                default:

                    console.log(input.semantic);
                    break;

            }

        }

        this.startTime = 0;
        this.endTime = 0;
        this.duration = 0;

        if ( this.input.length ) {

            this.startTime = 100000000;
            this.endTime = -100000000;

            for ( var i = 0; i < this.input.length; i ++ ) {

                this.startTime = Math.min( this.startTime, this.input[ i ] );
                this.endTime = Math.max( this.endTime, this.input[ i ] );

            }

            this.duration = this.endTime - this.startTime;

        }

    };

    Sampler.prototype.getData = function ( type, ndx, member ) {

        var data;

        if ( type === 'matrix' && this.strideOut === 16 ) {

            data = this.output[ ndx ];

        } else if ( this.strideOut > 1 ) {

            data = [];
            ndx *= this.strideOut;

            for ( var i = 0; i < this.strideOut; ++ i ) {

                data[ i ] = this.output[ ndx + i ];

            }

            if ( this.strideOut === 3 ) {

                switch ( type ) {

                    case 'rotate':
                    case 'translate':

                        fixCoords( data, -1 );
                        break;

                    case 'scale':

                        fixCoords( data, 1 );
                        break;

                }

            } else if ( this.strideOut === 4 && type === 'matrix' ) {

                fixCoords( data, -1 );

            }

        } else {

            data = this.output[ ndx ];

            if ( member && type === 'translate' ) {
                data = getConvertedTranslation( member, data );
            }

        }

        return data;

    };

    function Key ( time ) {

        this.targets = [];
        this.time = time;

    }

    Key.prototype.addTarget = function ( fullSid, transform, member, data ) {

        this.targets.push( {
            sid: fullSid,
            member: member,
            transform: transform,
            data: data
        } );

    };

    Key.prototype.apply = function ( opt_sid ) {

        for ( var i = 0; i < this.targets.length; ++ i ) {

            var target = this.targets[ i ];

            if ( !opt_sid || target.sid === opt_sid ) {

                target.transform.update( target.data, target.member );

            }

        }

    };

    Key.prototype.getTarget = function ( fullSid ) {

        for ( var i = 0; i < this.targets.length; ++ i ) {

            if ( this.targets[ i ].sid === fullSid ) {

                return this.targets[ i ];

            }

        }

        return null;

    };

    Key.prototype.hasTarget = function ( fullSid ) {

        for ( var i = 0; i < this.targets.length; ++ i ) {

            if ( this.targets[ i ].sid === fullSid ) {

                return true;

            }

        }

        return false;

    };

    // TODO: Currently only doing linear interpolation. Should support full COLLADA spec.
    Key.prototype.interpolate = function ( nextKey, time ) {

        for ( var i = 0, l = this.targets.length; i < l; i ++ ) {

            var target = this.targets[ i ],
                nextTarget = nextKey.getTarget( target.sid ),
                data;

            if ( target.transform.type !== 'matrix' && nextTarget ) {

                var scale = ( time - this.time ) / ( nextKey.time - this.time ),
                    nextData = nextTarget.data,
                    prevData = target.data;

                if ( scale < 0 ) scale = 0;
                if ( scale > 1 ) scale = 1;

                if ( prevData.length ) {

                    data = [];

                    for ( var j = 0; j < prevData.length; ++ j ) {

                        data[ j ] = prevData[ j ] + ( nextData[ j ] - prevData[ j ] ) * scale;

                    }

                } else {

                    data = prevData + ( nextData - prevData ) * scale;

                }

            } else {

                data = target.data;

            }

            target.transform.update( data, target.member );

        }

    };

    // Camera
    function Camera() {

        this.id = "";
        this.name = "";
        this.technique = "";

    }

    Camera.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'optics':

                    this.parseOptics( child );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    Camera.prototype.parseOptics = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            if ( element.childNodes[ i ].nodeName === 'technique_common' ) {

                var technique = element.childNodes[ i ];

                for ( var j = 0; j < technique.childNodes.length; j ++ ) {

                    this.technique = technique.childNodes[ j ].nodeName;

                    if ( this.technique === 'perspective' ) {

                        var perspective = technique.childNodes[ j ];

                        for ( var k = 0; k < perspective.childNodes.length; k ++ ) {

                            var param = perspective.childNodes[ k ];

                            switch ( param.nodeName ) {

                                case 'yfov':
                                    this.yfov = param.textContent;
                                    break;
                                case 'xfov':
                                    this.xfov = param.textContent;
                                    break;
                                case 'znear':
                                    this.znear = param.textContent;
                                    break;
                                case 'zfar':
                                    this.zfar = param.textContent;
                                    break;
                                case 'aspect_ratio':
                                    this.aspect_ratio = param.textContent;
                                    break;

                            }

                        }

                    } else if ( this.technique === 'orthographic' ) {

                        var orthographic = technique.childNodes[ j ];

                        for ( var k = 0; k < orthographic.childNodes.length; k ++ ) {

                            var param = orthographic.childNodes[ k ];

                            switch ( param.nodeName ) {

                                case 'xmag':
                                    this.xmag = param.textContent;
                                    break;
                                case 'ymag':
                                    this.ymag = param.textContent;
                                    break;
                                case 'znear':
                                    this.znear = param.textContent;
                                    break;
                                case 'zfar':
                                    this.zfar = param.textContent;
                                    break;
                                case 'aspect_ratio':
                                    this.aspect_ratio = param.textContent;
                                    break;

                            }

                        }

                    }

                }

            }

        }

        return this;

    };

    function InstanceCamera() {

        this.url = "";

    }

    InstanceCamera.prototype.parse = function ( element ) {

        this.url = element.getAttribute('url').replace(/^#/, '');

        return this;

    };

    // Light

    function Light() {

        this.id = "";
        this.name = "";
        this.technique = "";

    }

    Light.prototype.parse = function ( element ) {

        this.id = element.getAttribute( 'id' );
        this.name = element.getAttribute( 'name' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'technique_common':

                    this.parseCommon( child );
                    break;

                case 'technique':

                    this.parseTechnique( child );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    Light.prototype.parseCommon = function ( element ) {

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            switch ( element.childNodes[ i ].nodeName ) {

                case 'directional':
                case 'point':
                case 'spot':
                case 'ambient':

                    this.technique = element.childNodes[ i ].nodeName;

                    var light = element.childNodes[ i ];

                    for ( var j = 0; j < light.childNodes.length; j ++ ) {

                        var child = light.childNodes[j];

                        switch ( child.nodeName ) {

                            case 'color':

                                var rgba = _floats( child.textContent );
                                this.color = new THREE.Color(0);
                                this.color.setRGB( rgba[0], rgba[1], rgba[2] );
                                this.color.a = rgba[3];
                                break;

                            case 'falloff_angle':

                                this.falloff_angle = parseFloat( child.textContent );
                                break;

                            case 'quadratic_attenuation':
                                var f = parseFloat( child.textContent );
                                this.distance = f ? Math.sqrt( 1 / f ) : 0;
                        }

                    }

            }

        }

        return this;

    };

    Light.prototype.parseTechnique = function ( element ) {

        this.profile = element.getAttribute( 'profile' );

        for ( var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];

            switch ( child.nodeName ) {

                case 'intensity':

                    this.intensity = parseFloat(child.textContent);
                    break;

            }

        }

        return this;

    };

    function InstanceLight() {

        this.url = "";

    }

    InstanceLight.prototype.parse = function ( element ) {

        this.url = element.getAttribute('url').replace(/^#/, '');

        return this;

    };

    function KinematicsModel( ) {

        this.id = '';
        this.name = '';
        this.joints = [];
        this.links = [];

    }

    KinematicsModel.prototype.parse = function( element ) {

        this.id = element.getAttribute('id');
        this.name = element.getAttribute('name');
        this.joints = [];
        this.links = [];

        for (var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'technique_common':

                    this.parseCommon(child);
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    KinematicsModel.prototype.parseCommon = function( element ) {

        for (var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( element.childNodes[ i ].nodeName ) {

                case 'joint':
                    this.joints.push( (new Joint()).parse(child) );
                    break;

                case 'link':
                    this.links.push( (new Link()).parse(child) );
                    break;

                default:
                    break;

            }

        }

        return this;

    };

    function Joint( ) {

        this.sid = '';
        this.name = '';
        this.axis = new THREE.Vector3();
        this.limits = {
            min: 0,
            max: 0
        };
        this.type = '';
        this.static = false;
        this.zeroPosition = 0.0;
        this.middlePosition = 0.0;

    }

    Joint.prototype.parse = function( element ) {

        this.sid = element.getAttribute('sid');
        this.name = element.getAttribute('name');
        this.axis = new THREE.Vector3();
        this.limits = {
            min: 0,
            max: 0
        };
        this.type = '';
        this.static = false;
        this.zeroPosition = 0.0;
        this.middlePosition = 0.0;

        var axisElement = element.querySelector('axis');
        var _axis = _floats(axisElement.textContent);
        this.axis = getConvertedVec3(_axis, 0);

        var min = element.querySelector('limits min') ? parseFloat(element.querySelector('limits min').textContent) : -360;
        var max = element.querySelector('limits max') ? parseFloat(element.querySelector('limits max').textContent) : 360;

        this.limits = {
            min: min,
            max: max
        };

        var jointTypes = [ 'prismatic', 'revolute' ];
        for (var i = 0; i < jointTypes.length; i ++ ) {

            var type = jointTypes[ i ];

            var jointElement = element.querySelector(type);

            if ( jointElement ) {

                this.type = type;

            }

        }

        // if the min is equal to or somehow greater than the max, consider the joint static
        if ( this.limits.min >= this.limits.max ) {

            this.static = true;

        }

        this.middlePosition = (this.limits.min + this.limits.max) / 2.0;
        return this;

    };

    function Link( ) {

        this.sid = '';
        this.name = '';
        this.transforms = [];
        this.attachments = [];

    }

    Link.prototype.parse = function( element ) {

        this.sid = element.getAttribute('sid');
        this.name = element.getAttribute('name');
        this.transforms = [];
        this.attachments = [];

        for (var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'attachment_full':
                    this.attachments.push( (new Attachment()).parse(child) );
                    break;

                case 'rotate':
                case 'translate':
                case 'matrix':

                    this.transforms.push( (new Transform()).parse(child) );
                    break;

                default:

                    break;

            }

        }

        return this;

    };

    function Attachment( ) {

        this.joint = '';
        this.transforms = [];
        this.links = [];

    }

    Attachment.prototype.parse = function( element ) {

        this.joint = element.getAttribute('joint').split('/').pop();
        this.links = [];

        for (var i = 0; i < element.childNodes.length; i ++ ) {

            var child = element.childNodes[ i ];
            if ( child.nodeType != 1 ) continue;

            switch ( child.nodeName ) {

                case 'link':
                    this.links.push( (new Link()).parse(child) );
                    break;

                case 'rotate':
                case 'translate':
                case 'matrix':

                    this.transforms.push( (new Transform()).parse(child) );
                    break;

                default:

                    break;

            }

        }

        return this;

    };

    function _source( element ) {

        var id = element.getAttribute( 'id' );

        if ( sources[ id ] != undefined ) {

            return sources[ id ];

        }

        sources[ id ] = ( new Source(id )).parse( element );
        return sources[ id ];

    }

    function _nsResolver( nsPrefix ) {

        if ( nsPrefix === "dae" ) {

            return "http://www.collada.org/2005/11/COLLADASchema";

        }

        return null;

    }

    function _bools( str ) {

        var raw = _strings( str );
        var data = [];

        for ( var i = 0, l = raw.length; i < l; i ++ ) {

            data.push( (raw[i] === 'true' || raw[i] === '1') ? true : false );

        }

        return data;

    }

    function _floats( str ) {

        var raw = _strings(str);
        var data = [];

        for ( var i = 0, l = raw.length; i < l; i ++ ) {

            data.push( parseFloat( raw[ i ] ) );

        }

        return data;

    }

    function _ints( str ) {

        var raw = _strings( str );
        var data = [];

        for ( var i = 0, l = raw.length; i < l; i ++ ) {

            data.push( parseInt( raw[ i ], 10 ) );

        }

        return data;

    }

    function _strings( str ) {

        return ( str.length > 0 ) ? _trimString( str ).split( /\s+/ ) : [];

    }

    function _trimString( str ) {

        return str.replace( /^\s+/, "" ).replace( /\s+$/, "" );

    }

    function _attr_as_float( element, name, defaultValue ) {

        if ( element.hasAttribute( name ) ) {

            return parseFloat( element.getAttribute( name ) );

        } else {

            return defaultValue;

        }

    }

    function _attr_as_int( element, name, defaultValue ) {

        if ( element.hasAttribute( name ) ) {

            return parseInt( element.getAttribute( name ), 10) ;

        } else {

            return defaultValue;

        }

    }

    function _attr_as_string( element, name, defaultValue ) {

        if ( element.hasAttribute( name ) ) {

            return element.getAttribute( name );

        } else {

            return defaultValue;

        }

    }

    function _format_float( f, num ) {

        if ( f === undefined ) {

            var s = '0.';

            while ( s.length < num + 2 ) {

                s += '0';

            }

            return s;

        }

        num = num || 2;

        var parts = f.toString().split( '.' );
        parts[ 1 ] = parts.length > 1 ? parts[ 1 ].substr( 0, num ) : "0";

        while ( parts[ 1 ].length < num ) {

            parts[ 1 ] += '0';

        }

        return parts.join( '.' );

    }

    function loadTextureImage ( texture, url ) {

        var loader = new THREE.ImageLoader();

        loader.load( url, function ( image ) {

            texture.image = image;
            texture.needsUpdate = true;

        } );

    }

    function extractDoubleSided( obj, element ) {

        obj.doubleSided = false;

        var node = element.querySelectorAll('extra double_sided')[0];

        if ( node ) {

            if ( node && parseInt( node.textContent, 10 ) === 1 ) {

                obj.doubleSided = true;

            }

        }

    }

    // Up axis conversion

    function setUpConversion() {

        if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {

            upConversion = null;

        } else {

            switch ( colladaUp ) {

                case 'X':

                    upConversion = options.upAxis === 'Y' ? 'XtoY' : 'XtoZ';
                    break;

                case 'Y':

                    upConversion = options.upAxis === 'X' ? 'YtoX' : 'YtoZ';
                    break;

                case 'Z':

                    upConversion = options.upAxis === 'X' ? 'ZtoX' : 'ZtoY';
                    break;

            }

        }

    }

    function fixCoords( data, sign ) {

        if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {

            return;

        }

        switch ( upConversion ) {

            case 'XtoY':

                var tmp = data[ 0 ];
                data[ 0 ] = sign * data[ 1 ];
                data[ 1 ] = tmp;
                break;

            case 'XtoZ':

                var tmp = data[ 2 ];
                data[ 2 ] = data[ 1 ];
                data[ 1 ] = data[ 0 ];
                data[ 0 ] = tmp;
                break;

            case 'YtoX':

                var tmp = data[ 0 ];
                data[ 0 ] = data[ 1 ];
                data[ 1 ] = sign * tmp;
                break;

            case 'YtoZ':

                var tmp = data[ 1 ];
                data[ 1 ] = sign * data[ 2 ];
                data[ 2 ] = tmp;
                break;

            case 'ZtoX':

                var tmp = data[ 0 ];
                data[ 0 ] = data[ 1 ];
                data[ 1 ] = data[ 2 ];
                data[ 2 ] = tmp;
                break;

            case 'ZtoY':

                var tmp = data[ 1 ];
                data[ 1 ] = data[ 2 ];
                data[ 2 ] = sign * tmp;
                break;

        }

    }

    function getConvertedTranslation( axis, data ) {

        if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {

            return data;

        }

        switch ( axis ) {
            case 'X':
                data = upConversion === 'XtoY' ? data * -1 : data;
                break;
            case 'Y':
                data = upConversion === 'YtoZ' || upConversion === 'YtoX' ? data * -1 : data;
                break;
            case 'Z':
                data = upConversion === 'ZtoY' ? data * -1 : data ;
                break;
            default:
                break;
        }

        return data;
    }

    function getConvertedVec3( data, offset ) {

        var arr = [ data[ offset ], data[ offset + 1 ], data[ offset + 2 ] ];
        fixCoords( arr, -1 );
        return new THREE.Vector3( arr[ 0 ], arr[ 1 ], arr[ 2 ] );

    }

    function getConvertedMat4( data ) {

        if ( options.convertUpAxis ) {

            // First fix rotation and scale

            // Columns first
            var arr = [ data[ 0 ], data[ 4 ], data[ 8 ] ];
            fixCoords( arr, -1 );
            data[ 0 ] = arr[ 0 ];
            data[ 4 ] = arr[ 1 ];
            data[ 8 ] = arr[ 2 ];
            arr = [ data[ 1 ], data[ 5 ], data[ 9 ] ];
            fixCoords( arr, -1 );
            data[ 1 ] = arr[ 0 ];
            data[ 5 ] = arr[ 1 ];
            data[ 9 ] = arr[ 2 ];
            arr = [ data[ 2 ], data[ 6 ], data[ 10 ] ];
            fixCoords( arr, -1 );
            data[ 2 ] = arr[ 0 ];
            data[ 6 ] = arr[ 1 ];
            data[ 10 ] = arr[ 2 ];
            // Rows second
            arr = [ data[ 0 ], data[ 1 ], data[ 2 ] ];
            fixCoords( arr, -1 );
            data[ 0 ] = arr[ 0 ];
            data[ 1 ] = arr[ 1 ];
            data[ 2 ] = arr[ 2 ];
            arr = [ data[ 4 ], data[ 5 ], data[ 6 ] ];
            fixCoords( arr, -1 );
            data[ 4 ] = arr[ 0 ];
            data[ 5 ] = arr[ 1 ];
            data[ 6 ] = arr[ 2 ];
            arr = [ data[ 8 ], data[ 9 ], data[ 10 ] ];
            fixCoords( arr, -1 );
            data[ 8 ] = arr[ 0 ];
            data[ 9 ] = arr[ 1 ];
            data[ 10 ] = arr[ 2 ];

            // Now fix translation
            arr = [ data[ 3 ], data[ 7 ], data[ 11 ] ];
            fixCoords( arr, -1 );
            data[ 3 ] = arr[ 0 ];
            data[ 7 ] = arr[ 1 ];
            data[ 11 ] = arr[ 2 ];

        }

        return new THREE.Matrix4().set(
            data[0], data[1], data[2], data[3],
            data[4], data[5], data[6], data[7],
            data[8], data[9], data[10], data[11],
            data[12], data[13], data[14], data[15]
            );

    }

    function getConvertedIndex( index ) {

        if ( index > -1 && index < 3 ) {

            var members = [ 'X', 'Y', 'Z' ],
                indices = { X: 0, Y: 1, Z: 2 };

            index = getConvertedMember( members[ index ] );
            index = indices[ index ];

        }

        return index;

    }

    function getConvertedMember( member ) {

        if ( options.convertUpAxis ) {

            switch ( member ) {

                case 'X':

                    switch ( upConversion ) {

                        case 'XtoY':
                        case 'XtoZ':
                        case 'YtoX':

                            member = 'Y';
                            break;

                        case 'ZtoX':

                            member = 'Z';
                            break;

                    }

                    break;

                case 'Y':

                    switch ( upConversion ) {

                        case 'XtoY':
                        case 'YtoX':
                        case 'ZtoX':

                            member = 'X';
                            break;

                        case 'XtoZ':
                        case 'YtoZ':
                        case 'ZtoY':

                            member = 'Z';
                            break;

                    }

                    break;

                case 'Z':

                    switch ( upConversion ) {

                        case 'XtoZ':

                            member = 'X';
                            break;

                        case 'YtoZ':
                        case 'ZtoX':
                        case 'ZtoY':

                            member = 'Y';
                            break;

                    }

                    break;

            }

        }

        return member;

    }

    return {

        load: load,
        parse: parse,
        setPreferredShading: setPreferredShading,
        applySkin: applySkin,
        geometries : geometries,
        options: options

    };

};

module.exports = ColladaLoader;


/***/ }),
/* 214 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _midiPlayerJs = __webpack_require__(215);

var _midiPlayerJs2 = _interopRequireDefault(_midiPlayerJs);

var _soundfontPlayer = __webpack_require__(221);

var _soundfontPlayer2 = _interopRequireDefault(_soundfontPlayer);

var _reactPlayerControls = __webpack_require__(236);

var _reactSimpleFlexGrid = __webpack_require__(201);

var _reactIconsKit = __webpack_require__(245);

var _reactIconsKit2 = _interopRequireDefault(_reactIconsKit);

var _play = __webpack_require__(256);

var _pause = __webpack_require__(257);

var _copy = __webpack_require__(258);

var _heart = __webpack_require__(259);

__webpack_require__(202);

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 AudioContext = window.AudioContext || window.webkitAudioContext || false;

var MidiPlayerComponent = function (_Component) {
  _inherits(MidiPlayerComponent, _Component);

  function MidiPlayerComponent(props) {
    _classCallCheck(this, MidiPlayerComponent);

    var _this = _possibleConstructorReturn(this, (MidiPlayerComponent.__proto__ || Object.getPrototypeOf(MidiPlayerComponent)).call(this, props));

    _this.state = {
      submission_id: "something",
      isLoading: true,
      isPlayEnabled: false,
      hasPlayedOnce: false,
      isPauseEnabled: false,
      isHeartEnabled: false,
      isInstrument_loaded: false,
      isMIDIFileLoaded: false,
      isSeekable: true,
      isMuted: false,
      currentTime: 0,
      totalTime: 0,
      status_message: 'Loading Instruments 🎻 🎷 🎺 🎸 🥁 ...',
      largeIconSize: 50
    };

    _this.load_data_uri = _this.load_data_uri.bind(_this);
    _this.instrument_loaded = _this.instrument_loaded.bind(_this);
    _this.player_fileLoaded = _this.player_fileLoaded.bind(_this);
    _this.player_playing = _this.player_playing.bind(_this);
    _this.player_midiEvent = _this.player_midiEvent.bind(_this);
    _this.player_endOfFile = _this.player_endOfFile.bind(_this);
    _this.playSong = _this.playSong.bind(_this);
    _this.pauseSong = _this.pauseSong.bind(_this);
    _this.unlockAudioContext = _this.unlockAudioContext.bind(_this);
    _this.AudioContextUnlocked = false;

    _this.audio_context = new AudioContext();

    _this.instrument = false;

    _soundfontPlayer2.default.instrument(_this.audio_context, 'acoustic_grand_piano').then(_this.instrument_loaded);
    _this.Player = new _midiPlayerJs2.default.Player();
    _this.Player.on('fileLoaded', _this.player_fileLoaded);
    _this.Player.on('playing', _this.player_playing);
    _this.Player.on('midiEvent', _this.player_midiEvent);
    _this.Player.on('endOfFile', _this.player_endOfFile);
    // this.Player.playLoop(false);
    _this.note_states = {};

    return _this;
  }

  _createClass(MidiPlayerComponent, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.load_data_uri(this.props.dataUri);
    }
  }, {
    key: 'componentWillMount',
    value: function componentWillMount() {}
  }, {
    key: 'unlockAudioContext',
    value: function unlockAudioContext() {
      var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
      if (!iOS || this.AudioContextUnlocked) return;

      // create empty buffer and play it
      var buffer = this.audio_context.createBuffer(1, 1, 22050);
      var source = this.audio_context.createBufferSource();
      source.buffer = buffer;
      source.connect(this.audio_context.destination);
      if (source.start) {
        source.start(0);
      } else if (source.noteOn) {
        source.noteOn(0);
      }

      // by checking the play state after some time, we know if we're really unlocked
      setTimeout(function () {
        if (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE) {
          this.AudioContextUnlocked = true;
        }
      }, 0);
    }
  }, {
    key: 'player_fileLoaded',
    value: function player_fileLoaded() {
      //This is where the UI for Play/Pause etc will be enabled
      var totalTime = this.Player.getSongTime();
      // let currentTime = this.Player.getSongTime() - this.Player.getSongTimeRemaining();

      this.setState({ isMIDIFileLoaded: true, totalTime: totalTime, currentTime: 0, isPlayEnabled: this.state.isInstrument_loaded ? true : false, isPauseEnabled: false, status_message: "" });
      if (this.state.isInstrument_loaded && this.state.isMIDIFileLoaded) {
        this.setState({ isLoading: false });
      }
    }
  }, {
    key: 'player_playing',
    value: function player_playing(currentTick) {
      // console.log("Play Remainnig : ", this.Player.getSongTimeRemaining());
      var totalTime = this.Player.getSongTime();
      var currentTime = this.Player.getSongTime() - this.Player.getSongTimeRemaining();
      var isHeartEnabled = false;
      if (this.state.currentTime !== 0 && this.state.totalTime !== 0 && this.state.currentTime * 1.0 / this.state.totalTime > 0.2) {
        isHeartEnabled = true;
      }

      this.setState({
        totalTime: totalTime,
        hasPlayedOnce: true,
        currentTime: currentTime,
        isPlayEnabled: false,
        isPauseEnabled: true,
        isHeartEnabled: isHeartEnabled
      });

      if (this.Player.getSongTimeRemaining() <= 0) {
        this.player_endOfFile();
      }
    }
  }, {
    key: 'player_midiEvent',
    value: function player_midiEvent(event) {
      if (event.name === "Note on") {
        if (event.velocity <= 0) {
          //Register a NOTE_OFF
          this.props.onNoteOff(event.noteNumber);
          this.note_states[event.noteNumber] = 'stopped';
        } else {
          this.instrument.play(event.noteNumber, this.audio_context.current_time, { gain: event.velocity / 100.0 });
          this.props.onNoteOn(event.noteNumber);
          this.note_states[event.noteNumber] = 'playing';
          // Register a Note ON
        }
      } else if (event.name === "Note off") {
        // console.log(event);
        //Register a NoteOff
        this.props.onNoteOff(event.noteNumber);
        this.note_states[event.noteNumber] = 'stopped';
      }
    }
  }, {
    key: 'player_endOfFile',
    value: function player_endOfFile() {
      this.Player.skipToSeconds(0);
      this.Player.stop();
      this.setState({ isPlayEnabled: true, isPauseEnabled: false, currentTime: this.Player.getSongTime() });
      this.props.resetKeyBoard();
    }
  }, {
    key: 'instrument_loaded',
    value: function instrument_loaded(_instrument) {
      this.instrument = _instrument;
      this.setState({ isInstrument_loaded: true, isPlayEnabled: this.state.isMIDIFileLoaded ? true : false });
      if (this.state.isInstrument_loaded && this.state.isMIDIFileLoaded) {
        this.setState({ isLoading: false });
      }
    }
  }, {
    key: 'load_data_uri',
    value: function load_data_uri(dataUri) {
      if (dataUri && dataUri !== this.dataUri) {
        this.setState({ status_message: "Loading MIDI file.", isMIDIFileLoaded: false });
        this.Player.loadDataUri(dataUri);
        this.datUri = dataUri;
      }
    }
  }, {
    key: 'playSong',
    value: function playSong() {
      this.setState({ isPlayEnabled: false, isPauseEnabled: true });
      this.unlockAudioContext();
      this.Player.play();
    }
  }, {
    key: 'pauseSong',
    value: function pauseSong() {
      this.Player.pause();
      this.setState({ isPlayEnabled: true, isPauseEnabled: false });
      this.props.resetKeyBoard();
    }
  }, {
    key: 'onSeekStart',
    value: function onSeekStart(time) {
      this.pauseSong();
    }
  }, {
    key: 'onSeekEnd',
    value: function onSeekEnd(time) {
      this.Player.skipToSeconds(time);
      this.playSong();
    }
  }, {
    key: 'renderPlayPause',
    value: function renderPlayPause() {
      var _this2 = this;

      if (this.state.isPlayEnabled) {
        var THIS = this;
        return _react2.default.createElement(
          'button',
          {
            className: 'crowdai_music_challenge_btns',
            disabled: !this.state.isPlayEnabled,
            onClick: function onClick() {
              _this2.props.onPlay(_this2.props.playerName);
            },
            'data-rh': 'Play Song',
            'data-rh-at': 'left'
          },
          _react2.default.createElement(_reactIconsKit2.default, { icon: _play.play, size: this.state.largeIconSize })
        );
      } else if (this.state.isPauseEnabled) {
        return _react2.default.createElement(
          'button',
          {
            className: 'crowdai_music_challenge_btns',
            disabled: this.state.isPlayEnabled,
            onClick: this.pauseSong,
            'data-rh': 'Pause Song',
            'data-rh-at': 'left'
          },
          _react2.default.createElement(_reactIconsKit2.default, { icon: _pause.pause, size: this.state.largeIconSize })
        );
      } else {
        return _react2.default.createElement(
          'button',
          {
            className: 'crowdai_music_challenge_btns',
            disabled: !this.state.isPlayEnabled,
            onClick: function onClick() {
              _this2.props.onPlay(_this2.props.playerName);
            },
            'data-rh': 'Loading \uD83C\uDFB5',
            'data-rh-at': 'left'
          },
          _react2.default.createElement(_reactIconsKit2.default, { icon: _play.play, size: this.state.largeIconSize })
        );
      }
    }
  }, {
    key: 'renderProgressBar',
    value: function renderProgressBar() {
      var _this3 = this;

      return _react2.default.createElement(_reactPlayerControls.ProgressBar, {
        totalTime: this.state.totalTime,
        currentTime: this.state.currentTime,
        isSeekable: this.state.isSeekable,
        onSeek: function onSeek(time) {
          return _this3.setState(function () {
            return { currentTime: time };
          });
        },
        onSeekStart: this.onSeekStart.bind(this),
        onSeekEnd: this.onSeekEnd.bind(this)

        // onSeekStart={time => this.setState(() => ({ lastSeekStart: time }))}
        // onSeekEnd={time => this.setState(() => ({ lastSeekEnd: time }))}
        // onIntent={time => this.setState(() => ({ lastIntent: time }))}
      });
    }
  }, {
    key: 'renderTimeMarker',
    value: function renderTimeMarker() {
      return _react2.default.createElement(_reactPlayerControls.TimeMarker, {
        totalTime: this.state.totalTime,
        currentTime: Math.max(0, this.state.currentTime),
        markerSeparator: " / "
      });
    }
  }, {
    key: 'renderHeart',
    value: function renderHeart() {
      var _this4 = this;

      return _react2.default.createElement(
        'button',
        {
          className: 'crowdai_music_challenge_btns share_button',
          disabled: !this.state.isHeartEnabled,
          'data-rh': this.state.isHeartEnabled ? "Vote for this song !" : "You can vote for this song only after listening to it ;)",
          'data-rh-at': 'bottom',
          onClick: function onClick() {
            _this4.props.onHeartClicked(_this4.props.playerName);
          }
        },
        _react2.default.createElement(_reactIconsKit2.default, { icon: _heart.heart, size: this.state.largeIconSize })
      );
    }
  }, {
    key: 'renderSubmissionID',
    value: function renderSubmissionID() {
      if (this.state.submission_id) {
        return _react2.default.createElement(
          'pre',
          null,
          _react2.default.createElement(
            'strong',
            null,
            '#song',
            this.props.playerName + 1
          ),
          ' : ',
          this.state.submission_id.slice(0, 13)
        );
      } else {
        return _react2.default.createElement(
          'pre',
          null,
          "...."
        );
      }
    }
  }, {
    key: 'renderTopRow',
    value: function renderTopRow() {
      if (!this.state.isLoading) {
        return _react2.default.createElement(
          'div',
          null,
          _react2.default.createElement(
            _reactSimpleFlexGrid.Row,
            { gutter: '20', justify: 'center' },
            this.renderSubmissionID()
          ),
          _react2.default.createElement(
            _reactSimpleFlexGrid.Row,
            { gutter: '20', justify: 'center' },
            _react2.default.createElement(
              _reactSimpleFlexGrid.Col,
              { className: '', xs: { span: 5 }, sm: { span: 4 }, md: { span: 3 }, lg: { span: 3 }, xl: { span: 3 } },
              this.renderPlayPause()
            ),
            _react2.default.createElement(
              _reactSimpleFlexGrid.Col,
              { className: '', xs: { span: 5 }, sm: { span: 4 }, md: { span: 3 }, lg: { span: 3 }, xl: { span: 3 } },
              this.renderHeart()
            )
          )
        );
      } else {
        return _react2.default.createElement(
          _reactSimpleFlexGrid.Row,
          { gutter: 10, align: 'middle', justify: 'center' },
          _react2.default.createElement('div', { className: 'crowdai_interface_loader' })
        );
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var active_state = "controlsWrapper_notactive";
      if (this.state.isPauseEnabled) {
        active_state = " controlsWrapper_active";
      }
      return _react2.default.createElement(
        'div',
        { className: "controlsWrapper " + active_state },
        this.renderTopRow(),
        _react2.default.createElement(
          _reactSimpleFlexGrid.Row,
          { align: 'middle', justify: 'center' },
          _react2.default.createElement(
            _reactSimpleFlexGrid.Col,
            { xs: 7, sm: 7, md: 7, lg: 8, xl: 10 },
            this.renderProgressBar()
          ),
          _react2.default.createElement(
            _reactSimpleFlexGrid.Col,
            { sm: 3, md: 3, lg: 2, xl: 1 },
            this.renderTimeMarker()
          ),
          _react2.default.createElement(
            _reactSimpleFlexGrid.Col,
            { className: 'hidden-xs', xs: 1, sm: 2, md: 2, lg: 2, xl: 1 },
            _react2.default.createElement(
              'button',
              {
                className: 'crowdai_music_challenge_btns share_button',
                disabled: true,
                'data-rh': 'Unique link to this song',
                'data-rh-at': 'bottom'
              },
              _react2.default.createElement(_reactIconsKit2.default, { icon: _copy.copy })
            )
          )
        )
      );
    }
  }]);

  return MidiPlayerComponent;
}(_react.Component);

MidiPlayerComponent.defaultProps = {
  playOnLoad: false
  // dataUri: "data:audio/midi;base64,TVRoZAAAAAYAAQACAQBNVHJrAAAAGgD/WAQEAhgIAP9ZAv8AAP9YBAMCGAgB/y8ATVRyawAAAagAsFsyALAKSQCwWzIAsApJALAAAACwIAAAwAAAkDxGgS2QPAATkDxIOpA8AAaQPlMAkDVJAJA5SIFnkD4AGZA8SIFnkDwAGZBBVYFOkDUAAJA5ABmQQQAZkEBPAJAwUQCQOlGDTpBAADKQPEeBLZA8ABOQPEgOkDAAAJA6ACyQPAAGkD5VAJAwUACQOk+BZ5A+ABmQPEWBZ5A8ABmQQ1qBTpAwAACQOgAZkEMAGZBBSwCQNUkAkDlJg06QQQAykDxFgS2QPAATkDxKDpA1AACQOQAskDwABpBIYwCQNU0AkDlPgWeQSAAZkEVKgWeQRQAZkEFCgU6QNQAAkDkAGZBBABmQQEkAkDVRAJA6VIFnkEAAGZA+RYFH/1EDOThwIJA+AAD/UQMJJ8AZkEZZgS2QRgAB/1EDOThwEpBGTg6QNQAAkDoAAP9RAwknwCyQRgAGkEVMAJA1SwCQOUuBZ5BFABmQQUGBTpA1AACQOQAZkEEAGZBDTQCQME4AkDpPgWeQQwAAkDAAAJA6ABmQQUkAkDVMAJA5TIVOkEEAAJA1AACQOQAB/y8A"
};
exports.default = MidiPlayerComponent;

/***/ }),
/* 215 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(Buffer) {

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

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; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Constants = {
    VERSION: '1.1.4',
    NOTES: []
};

(function () {
    var allNotes = [['C'], ['C#', 'Db'], ['D'], ['D#', 'Eb'], ['E'], ['F'], ['F#', 'Gb'], ['G'], ['G#', 'Ab'], ['A'], ['A#', 'Bb'], ['B']];
    var counter = 0;

    var _loop = function _loop(i) {
        allNotes.forEach(function (noteGroup) {
            noteGroup.forEach(function (note) {
                return Constants.NOTES[counter] = note + i;
            });
            counter++;
        });
    };

    for (var i = -1; i <= 9; i++) {
        _loop(i);
    }
})();

exports.Constants = Constants;
var Player = function () {
    function Player(eventHandler, buffer) {
        _classCallCheck(this, Player);

        this.sampleRate = 5;
        this.startTime = 0;
        this.buffer = buffer || null;
        this.division;
        this.format;
        this.setIntervalId = false;
        this.tracks = [];
        this.tempo = 120;
        this.startTick = 0;
        this.tick = 0;
        this.lastTick = null;
        this.inLoop = false;
        this.totalTicks = 0;
        this.events = [];
        this.totalEvents = 0;
        this.eventListeners = {};

        if (typeof eventHandler === 'function') this.on('midiEvent', eventHandler);
    }

    _createClass(Player, [{
        key: 'loadFile',
        value: function loadFile(path) {
            var fs = __webpack_require__(220);
            this.buffer = fs.readFileSync(path);
            return this.fileLoaded();
        }
    }, {
        key: 'loadArrayBuffer',
        value: function loadArrayBuffer(arrayBuffer) {
            this.buffer = new Uint8Array(arrayBuffer);
            return this.fileLoaded();
        }
    }, {
        key: 'loadDataUri',
        value: function loadDataUri(dataUri) {
            var byteString = Utils.atob(dataUri.split(',')[1]);

            var ia = new Uint8Array(byteString.length);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }

            this.buffer = ia;
            return this.fileLoaded();
        }
    }, {
        key: 'getFilesize',
        value: function getFilesize() {
            return this.buffer ? this.buffer.length : 0;
        }
    }, {
        key: 'fileLoaded',
        value: function fileLoaded() {
            if (!this.validate()) throw 'Invalid MIDI file; should start with MThd';
            return this.getDivision().getFormat().getTracks().dryRun();
        }
    }, {
        key: 'validate',
        value: function validate() {
            return Utils.bytesToLetters(this.buffer.slice(0, 4)) === 'MThd';
        }
    }, {
        key: 'getFormat',
        value: function getFormat() {

            this.format = Utils.bytesToNumber(this.buffer.slice(8, 10));
            return this;
        }
    }, {
        key: 'getTracks',
        value: function getTracks() {
            this.tracks = [];
            this.buffer.forEach(function (byte, index) {
                if (Utils.bytesToLetters(this.buffer.slice(index, index + 4)) == 'MTrk') {
                    var trackLength = Utils.bytesToNumber(this.buffer.slice(index + 4, index + 8));
                    this.tracks.push(new Track(this.tracks.length, this.buffer.slice(index + 8, index + 8 + trackLength)));
                }
            }, this);

            return this;
        }
    }, {
        key: 'enableTrack',
        value: function enableTrack(trackNumber) {
            this.tracks[trackNumber - 1].enable();
            return this;
        }
    }, {
        key: 'disableTrack',
        value: function disableTrack(trackNumber) {
            this.tracks[trackNumber - 1].disable();
            return this;
        }
    }, {
        key: 'getDivision',
        value: function getDivision() {
            this.division = Utils.bytesToNumber(this.buffer.slice(12, 14));
            return this;
        }
    }, {
        key: 'playLoop',
        value: function playLoop(dryRun) {
            if (!this.inLoop) {
                this.inLoop = true;
                this.tick = this.getCurrentTick();

                this.tracks.forEach(function (track) {
                    if (!dryRun && this.endOfFile()) {
                        this.triggerPlayerEvent('endOfFile');
                        this.stop();
                    } else {
                        var _event = track.handleEvent(this.tick, dryRun);

                        if (dryRun && _event && _event.hasOwnProperty('name') && _event.name === 'Set Tempo') {
                            this.tempo = _event.data;
                        }

                        if (_event && !dryRun) this.emitEvent(_event);
                    }
                }, this);

                if (!dryRun) this.triggerPlayerEvent('playing', { tick: this.tick });
                this.inLoop = false;
            }
        }
    }, {
        key: 'setStartTime',
        value: function setStartTime(startTime) {
            this.startTime = startTime;
        }
    }, {
        key: 'play',
        value: function play() {
            if (this.isPlaying()) throw 'Already playing...';

            if (!this.startTime) this.startTime = new Date().getTime();

            this.setIntervalId = setInterval(this.playLoop.bind(this), this.sampleRate);

            return this;
        }
    }, {
        key: 'pause',
        value: function pause() {
            clearInterval(this.setIntervalId);
            this.setIntervalId = false;
            this.startTick = this.tick;
            this.startTime = 0;
            return this;
        }
    }, {
        key: 'stop',
        value: function stop() {
            clearInterval(this.setIntervalId);
            this.setIntervalId = false;
            this.startTick = 0;
            this.startTime = 0;
            this.resetTracks();
            return this;
        }
    }, {
        key: 'skipToTick',
        value: function skipToTick(tick) {
            this.stop();
            this.startTick = tick;

            this.tracks.forEach(function (track) {
                track.setEventIndexByTick(tick);
            });
            return this;
        }
    }, {
        key: 'skipToPercent',
        value: function skipToPercent(percent) {
            if (percent < 0 || percent > 100) throw "Percent must be number between 1 and 100.";
            this.skipToTick(Math.round(percent / 100 * this.totalTicks));
            return this;
        }
    }, {
        key: 'skipToSeconds',
        value: function skipToSeconds(seconds) {
            var songTime = this.getSongTime();
            if (seconds < 0 || seconds > songTime) throw seconds + " seconds not within song time of " + songTime;
            this.skipToPercent(seconds / songTime * 100);
            return this;
        }
    }, {
        key: 'isPlaying',
        value: function isPlaying() {
            return this.setIntervalId > 0 || _typeof(this.setIntervalId) === 'object';
        }
    }, {
        key: 'dryRun',
        value: function dryRun() {
            this.resetTracks();
            while (!this.endOfFile()) {
                this.playLoop(true);
            }this.events = this.getEvents();
            this.totalEvents = this.getTotalEvents();
            this.totalTicks = this.getTotalTicks();
            this.startTick = 0;
            this.startTime = 0;

            this.resetTracks();

            this.triggerPlayerEvent('fileLoaded', this);
            return this;
        }
    }, {
        key: 'resetTracks',
        value: function resetTracks() {
            this.tracks.forEach(function (track) {
                return track.reset();
            });
            return this;
        }
    }, {
        key: 'getEvents',
        value: function getEvents() {
            return this.tracks.map(function (track) {
                return track.events;
            });
        }
    }, {
        key: 'getTotalTicks',
        value: function getTotalTicks() {
            return Math.max.apply(null, this.tracks.map(function (track) {
                return track.delta;
            }));
        }
    }, {
        key: 'getTotalEvents',
        value: function getTotalEvents() {
            return this.tracks.reduce(function (a, b) {
                return { events: { length: a.events.length + b.events.length } };
            }, { events: { length: 0 } }).events.length;
        }
    }, {
        key: 'getSongTime',
        value: function getSongTime() {
            return this.totalTicks / this.division / this.tempo * 60;
        }
    }, {
        key: 'getSongTimeRemaining',
        value: function getSongTimeRemaining() {
            return Math.round((this.totalTicks - this.tick) / this.division / this.tempo * 60);
        }
    }, {
        key: 'getSongPercentRemaining',
        value: function getSongPercentRemaining() {
            return Math.round(this.getSongTimeRemaining() / this.getSongTime() * 100);
        }
    }, {
        key: 'bytesProcessed',
        value: function bytesProcessed() {
            return 14 + this.tracks.length * 8 + this.tracks.reduce(function (a, b) {
                return { pointer: a.pointer + b.pointer };
            }, { pointer: 0 }).pointer;
        }
    }, {
        key: 'eventsPlayed',
        value: function eventsPlayed() {
            return this.tracks.reduce(function (a, b) {
                return { eventIndex: a.eventIndex + b.eventIndex };
            }, { eventIndex: 0 }).eventIndex;
        }
    }, {
        key: 'endOfFile',
        value: function endOfFile() {
            if (this.isPlaying()) {
                return this.eventsPlayed() == this.totalEvents;
            }

            return this.bytesProcessed() == this.buffer.length;
        }
    }, {
        key: 'getCurrentTick',
        value: function getCurrentTick() {
            return Math.round((new Date().getTime() - this.startTime) / 1000 * (this.division * (this.tempo / 60))) + this.startTick;
        }
    }, {
        key: 'emitEvent',
        value: function emitEvent(event) {
            this.triggerPlayerEvent('midiEvent', event);
            return this;
        }
    }, {
        key: 'on',
        value: function on(playerEvent, fn) {
            if (!this.eventListeners.hasOwnProperty(playerEvent)) this.eventListeners[playerEvent] = [];
            this.eventListeners[playerEvent].push(fn);
            return this;
        }
    }, {
        key: 'triggerPlayerEvent',
        value: function triggerPlayerEvent(playerEvent, data) {
            if (this.eventListeners.hasOwnProperty(playerEvent)) this.eventListeners[playerEvent].forEach(function (fn) {
                return fn(data || {});
            });
            return this;
        }
    }]);

    return Player;
}();

exports.Player = Player;

var Track = function () {
    function Track(index, data) {
        _classCallCheck(this, Track);

        this.enabled = true;
        this.eventIndex = 0;
        this.pointer = 0;
        this.lastTick = 0;
        this.lastStatus = null;
        this.index = index;
        this.data = data;
        this.delta = 0;
        this.runningDelta = 0;
        this.events = [];
    }

    _createClass(Track, [{
        key: 'reset',
        value: function reset() {
            this.enabled = true;
            this.eventIndex = 0;
            this.pointer = 0;
            this.lastTick = 0;
            this.lastStatus = null;
            this.delta = 0;
            this.runningDelta = 0;
            return this;
        }
    }, {
        key: 'enable',
        value: function enable() {
            this.enabled = true;
            return this;
        }
    }, {
        key: 'disable',
        value: function disable() {
            this.enabled = false;
            return this;
        }
    }, {
        key: 'setEventIndexByTick',
        value: function setEventIndexByTick(tick) {
            tick = tick || 0;

            for (var i in this.events) {
                if (this.events[i].tick >= tick) {
                    this.eventIndex = i;
                    return this;
                }
            }
        }
    }, {
        key: 'getCurrentByte',
        value: function getCurrentByte() {
            return this.data[this.pointer];
        }
    }, {
        key: 'getDeltaByteCount',
        value: function getDeltaByteCount() {
            var currentByte = this.getCurrentByte();
            var byteCount = 1;

            while (currentByte >= 128) {
                currentByte = this.data[this.pointer + byteCount];
                byteCount++;
            }

            return byteCount;
        }
    }, {
        key: 'getDelta',
        value: function getDelta() {
            return Utils.readVarInt(this.data.slice(this.pointer, this.pointer + this.getDeltaByteCount()));
        }
    }, {
        key: 'handleEvent',
        value: function handleEvent(currentTick, dryRun) {
            dryRun = dryRun || false;

            if (dryRun) {
                var elapsedTicks = currentTick - this.lastTick;
                var delta = this.getDelta();
                var eventReady = elapsedTicks >= delta;

                if (this.pointer < this.data.length && (dryRun || eventReady)) {
                    var _event2 = this.parseEvent();
                    if (this.enabled) return _event2;
                }
            } else {
                if (this.events[this.eventIndex] && this.events[this.eventIndex].tick <= currentTick) {
                    this.eventIndex++;
                    if (this.enabled) return this.events[this.eventIndex - 1];
                }
            }

            return null;
        }
    }, {
        key: 'getStringData',
        value: function getStringData(eventStartIndex) {
            var currentByte = this.pointer;
            var byteCount = 1;
            var length = Utils.readVarInt(this.data.slice(eventStartIndex + 2, eventStartIndex + 2 + byteCount));
            var stringLength = length;

            return Utils.bytesToLetters(this.data.slice(eventStartIndex + byteCount + 2, eventStartIndex + byteCount + length + 2));
        }
    }, {
        key: 'parseEvent',
        value: function parseEvent() {
            var eventStartIndex = this.pointer + this.getDeltaByteCount();
            var eventJson = {};
            var deltaByteCount = this.getDeltaByteCount();
            eventJson.track = this.index + 1;
            eventJson.delta = this.getDelta();
            this.lastTick = this.lastTick + eventJson.delta;
            this.runningDelta += eventJson.delta;
            eventJson.tick = this.runningDelta;
            eventJson.byteIndex = this.pointer;

            if (this.data[eventStartIndex] == 0xff) {

                switch (this.data[eventStartIndex + 1]) {
                    case 0x00:
                        eventJson.name = 'Sequence Number';
                        break;
                    case 0x01:
                        eventJson.name = 'Text Event';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x02:
                        eventJson.name = 'Copyright Notice';
                        break;
                    case 0x03:
                        eventJson.name = 'Sequence/Track Name';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x04:
                        eventJson.name = 'Instrument Name';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x05:
                        eventJson.name = 'Lyric';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x06:
                        eventJson.name = 'Marker';
                        break;
                    case 0x07:
                        eventJson.name = 'Cue Point';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x09:
                        eventJson.name = 'Device Name';
                        eventJson.string = this.getStringData(eventStartIndex);
                        break;
                    case 0x20:
                        eventJson.name = 'MIDI Channel Prefix';
                        break;
                    case 0x21:
                        eventJson.name = 'MIDI Port';
                        eventJson.data = Utils.bytesToNumber([this.data[eventStartIndex + 3]]);
                        break;
                    case 0x2F:
                        eventJson.name = 'End of Track';
                        break;
                    case 0x51:
                        eventJson.name = 'Set Tempo';
                        eventJson.data = Math.round(60000000 / Utils.bytesToNumber(this.data.slice(eventStartIndex + 3, eventStartIndex + 6)));
                        this.tempo = eventJson.data;
                        break;
                    case 0x54:
                        eventJson.name = 'SMTPE Offset';
                        break;
                    case 0x58:
                        eventJson.name = 'Time Signature';
                        break;
                    case 0x59:
                        eventJson.name = 'Key Signature';
                        break;
                    case 0x7F:
                        eventJson.name = 'Sequencer-Specific Meta-event';
                        break;
                    default:
                        eventJson.name = 'Unknown: ' + this.data[eventStartIndex + 1].toString(16);
                        break;
                }

                var length = this.data[this.pointer + deltaByteCount + 2];


                this.pointer += deltaByteCount + 3 + length;
            } else if (this.data[eventStartIndex] == 0xf0) {
                eventJson.name = 'Sysex';
                var length = this.data[this.pointer + deltaByteCount + 1];
                this.pointer += deltaByteCount + 2 + length;
            } else {
                if (this.data[eventStartIndex] < 0x80) {
                    eventJson.running = true;
                    eventJson.noteNumber = this.data[eventStartIndex];
                    eventJson.noteName = Constants.NOTES[this.data[eventStartIndex]];
                    eventJson.velocity = this.data[eventStartIndex + 1];

                    if (this.lastStatus <= 0x8f) {
                        eventJson.name = 'Note off';
                        eventJson.channel = this.lastStatus - 0x80 + 1;
                    } else if (this.lastStatus <= 0x9f) {
                        eventJson.name = 'Note on';
                        eventJson.channel = this.lastStatus - 0x90 + 1;
                    }

                    this.pointer += deltaByteCount + 2;
                } else {
                    this.lastStatus = this.data[eventStartIndex];

                    if (this.data[eventStartIndex] <= 0x8f) {
                        eventJson.name = 'Note off';
                        eventJson.channel = this.lastStatus - 0x80 + 1;
                        eventJson.noteNumber = this.data[eventStartIndex + 1];
                        eventJson.noteName = Constants.NOTES[this.data[eventStartIndex + 1]];
                        eventJson.velocity = Math.round(this.data[eventStartIndex + 2] / 127 * 100);
                        this.pointer += deltaByteCount + 3;
                    } else if (this.data[eventStartIndex] <= 0x9f) {
                        eventJson.name = 'Note on';
                        eventJson.channel = this.lastStatus - 0x90 + 1;
                        eventJson.noteNumber = this.data[eventStartIndex + 1];
                        eventJson.noteName = Constants.NOTES[this.data[eventStartIndex + 1]];
                        eventJson.velocity = Math.round(this.data[eventStartIndex + 2] / 127 * 100);
                        this.pointer += deltaByteCount + 3;
                    } else if (this.data[eventStartIndex] <= 0xaf) {
                        eventJson.name = 'Polyphonic Key Pressure';
                        eventJson.channel = this.lastStatus - 0xa0 + 1;
                        eventJson.note = Constants.NOTES[this.data[eventStartIndex + 1]];
                        eventJson.pressure = event[2];
                        this.pointer += deltaByteCount + 3;
                    } else if (this.data[eventStartIndex] <= 0xbf) {
                        eventJson.name = 'Controller Change';
                        eventJson.channel = this.lastStatus - 0xb0 + 1;
                        eventJson.number = this.data[eventStartIndex + 1];
                        eventJson.value = this.data[eventStartIndex + 2];
                        this.pointer += deltaByteCount + 3;
                    } else if (this.data[eventStartIndex] <= 0xcf) {
                        eventJson.name = 'Program Change';
                        eventJson.channel = this.lastStatus - 0xc0 + 1;
                        this.pointer += deltaByteCount + 2;
                    } else if (this.data[eventStartIndex] <= 0xdf) {
                        eventJson.name = 'Channel Key Pressure';
                        eventJson.channel = this.lastStatus - 0xd0 + 1;
                        this.pointer += deltaByteCount + 2;
                    } else if (this.data[eventStartIndex] <= 0xef) {
                        eventJson.name = 'Pitch Bend';
                        eventJson.channel = this.lastStatus - 0xe0 + 1;
                        this.pointer += deltaByteCount + 3;
                    } else {
                        eventJson.name = 'Unknown.  Pointer: ' + this.pointer.toString() + ' ' + eventStartIndex.toString() + ' ' + this.data.length;
                    }
                }
            }

            this.delta += eventJson.delta;
            this.events.push(eventJson);

            return eventJson;
        }
    }, {
        key: 'endOfTrack',
        value: function endOfTrack() {
            if (this.data[this.pointer + 1] == 0xff && this.data[this.pointer + 2] == 0x2f && this.data[this.pointer + 3] == 0x00) {
                return true;
            }

            return false;
        }
    }]);

    return Track;
}();

var Utils = function () {
    function Utils() {
        _classCallCheck(this, Utils);
    }

    _createClass(Utils, null, [{
        key: 'byteToHex',
        value: function byteToHex(byte) {
            return ('0' + byte.toString(16)).slice(-2);
        }
    }, {
        key: 'bytesToHex',
        value: function bytesToHex(byteArray) {
            var hex = [];
            byteArray.forEach(function (byte) {
                return hex.push(Utils.byteToHex(byte));
            });
            return hex.join('');
        }
    }, {
        key: 'hexToNumber',
        value: function hexToNumber(hexString) {
            return parseInt(hexString, 16);
        }
    }, {
        key: 'bytesToNumber',
        value: function bytesToNumber(byteArray) {
            return Utils.hexToNumber(Utils.bytesToHex(byteArray));
        }
    }, {
        key: 'bytesToLetters',
        value: function bytesToLetters(byteArray) {
            var letters = [];
            byteArray.forEach(function (byte) {
                return letters.push(String.fromCharCode(byte));
            });
            return letters.join('');
        }
    }, {
        key: 'decToBinary',
        value: function decToBinary(dec) {
            return (dec >>> 0).toString(2);
        }
    }, {
        key: 'readVarInt',
        value: function readVarInt(byteArray) {
            var result = 0;
            byteArray.forEach(function (number) {
                var b = number;
                if (b & 0x80) {
                    result += b & 0x7f;
                    result <<= 7;
                } else {
                    result += b;
                }
            });

            return result;
        }
    }, {
        key: 'atob',
        value: function (_atob) {
            function atob(_x) {
                return _atob.apply(this, arguments);
            }

            atob.toString = function () {
                return _atob.toString();
            };

            return atob;
        }(function (string) {
            if (typeof atob === 'function') return atob(string);
            return new Buffer(string, 'base64').toString('binary');
        })
    }]);

    return Utils;
}();

exports.Utils = Utils;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbIkNvbnN0YW50cyIsIlZFUlNJT04iLCJOT1RFUyIsImFsbE5vdGVzIiwiY291bnRlciIsImkiLCJmb3JFYWNoIiwibm90ZUdyb3VwIiwibm90ZSIsImV4cG9ydHMiLCJQbGF5ZXIiLCJldmVudEhhbmRsZXIiLCJidWZmZXIiLCJzYW1wbGVSYXRlIiwic3RhcnRUaW1lIiwiZGl2aXNpb24iLCJmb3JtYXQiLCJzZXRJbnRlcnZhbElkIiwidHJhY2tzIiwidGVtcG8iLCJzdGFydFRpY2siLCJ0aWNrIiwibGFzdFRpY2siLCJpbkxvb3AiLCJ0b3RhbFRpY2tzIiwiZXZlbnRzIiwidG90YWxFdmVudHMiLCJldmVudExpc3RlbmVycyIsIm9uIiwicGF0aCIsImZzIiwicmVxdWlyZSIsInJlYWRGaWxlU3luYyIsImZpbGVMb2FkZWQiLCJhcnJheUJ1ZmZlciIsIlVpbnQ4QXJyYXkiLCJkYXRhVXJpIiwiYnl0ZVN0cmluZyIsIlV0aWxzIiwiYXRvYiIsInNwbGl0IiwiaWEiLCJsZW5ndGgiLCJjaGFyQ29kZUF0IiwidmFsaWRhdGUiLCJnZXREaXZpc2lvbiIsImdldEZvcm1hdCIsImdldFRyYWNrcyIsImRyeVJ1biIsImJ5dGVzVG9MZXR0ZXJzIiwic2xpY2UiLCJieXRlc1RvTnVtYmVyIiwiYnl0ZSIsImluZGV4IiwidHJhY2tMZW5ndGgiLCJwdXNoIiwiVHJhY2siLCJ0cmFja051bWJlciIsImVuYWJsZSIsImRpc2FibGUiLCJnZXRDdXJyZW50VGljayIsInRyYWNrIiwiZW5kT2ZGaWxlIiwidHJpZ2dlclBsYXllckV2ZW50Iiwic3RvcCIsImV2ZW50IiwiaGFuZGxlRXZlbnQiLCJoYXNPd25Qcm9wZXJ0eSIsIm5hbWUiLCJkYXRhIiwiZW1pdEV2ZW50IiwiaXNQbGF5aW5nIiwiRGF0ZSIsImdldFRpbWUiLCJzZXRJbnRlcnZhbCIsInBsYXlMb29wIiwiYmluZCIsImNsZWFySW50ZXJ2YWwiLCJyZXNldFRyYWNrcyIsInNldEV2ZW50SW5kZXhCeVRpY2siLCJwZXJjZW50Iiwic2tpcFRvVGljayIsIk1hdGgiLCJyb3VuZCIsInNlY29uZHMiLCJzb25nVGltZSIsImdldFNvbmdUaW1lIiwic2tpcFRvUGVyY2VudCIsImdldEV2ZW50cyIsImdldFRvdGFsRXZlbnRzIiwiZ2V0VG90YWxUaWNrcyIsInJlc2V0IiwibWFwIiwibWF4IiwiYXBwbHkiLCJkZWx0YSIsInJlZHVjZSIsImEiLCJiIiwiZ2V0U29uZ1RpbWVSZW1haW5pbmciLCJwb2ludGVyIiwiZXZlbnRJbmRleCIsImV2ZW50c1BsYXllZCIsImJ5dGVzUHJvY2Vzc2VkIiwicGxheWVyRXZlbnQiLCJmbiIsImVuYWJsZWQiLCJsYXN0U3RhdHVzIiwicnVubmluZ0RlbHRhIiwiY3VycmVudEJ5dGUiLCJnZXRDdXJyZW50Qnl0ZSIsImJ5dGVDb3VudCIsInJlYWRWYXJJbnQiLCJnZXREZWx0YUJ5dGVDb3VudCIsImN1cnJlbnRUaWNrIiwiZWxhcHNlZFRpY2tzIiwiZ2V0RGVsdGEiLCJldmVudFJlYWR5IiwicGFyc2VFdmVudCIsImV2ZW50U3RhcnRJbmRleCIsInN0cmluZ0xlbmd0aCIsImV2ZW50SnNvbiIsImRlbHRhQnl0ZUNvdW50IiwiYnl0ZUluZGV4Iiwic3RyaW5nIiwiZ2V0U3RyaW5nRGF0YSIsInRvU3RyaW5nIiwicnVubmluZyIsIm5vdGVOdW1iZXIiLCJub3RlTmFtZSIsInZlbG9jaXR5IiwiY2hhbm5lbCIsInByZXNzdXJlIiwibnVtYmVyIiwidmFsdWUiLCJieXRlQXJyYXkiLCJoZXgiLCJieXRlVG9IZXgiLCJqb2luIiwiaGV4U3RyaW5nIiwicGFyc2VJbnQiLCJoZXhUb051bWJlciIsImJ5dGVzVG9IZXgiLCJsZXR0ZXJzIiwiU3RyaW5nIiwiZnJvbUNoYXJDb2RlIiwiZGVjIiwicmVzdWx0IiwiQnVmZmVyIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUdBLElBQUlBLFlBQVk7QUFDZkMsVUFBUyxPQURNO0FBRWZDLFFBQU87QUFGUSxDQUFoQjs7QUFLQSxDQUFDLFlBQVc7QUFFWCxLQUFJQyxXQUFXLENBQUMsQ0FBQyxHQUFELENBQUQsRUFBUSxDQUFDLElBQUQsRUFBTSxJQUFOLENBQVIsRUFBcUIsQ0FBQyxHQUFELENBQXJCLEVBQTRCLENBQUMsSUFBRCxFQUFNLElBQU4sQ0FBNUIsRUFBeUMsQ0FBQyxHQUFELENBQXpDLEVBQStDLENBQUMsR0FBRCxDQUEvQyxFQUFzRCxDQUFDLElBQUQsRUFBTSxJQUFOLENBQXRELEVBQW1FLENBQUMsR0FBRCxDQUFuRSxFQUEwRSxDQUFDLElBQUQsRUFBTSxJQUFOLENBQTFFLEVBQXVGLENBQUMsR0FBRCxDQUF2RixFQUE4RixDQUFDLElBQUQsRUFBTSxJQUFOLENBQTlGLEVBQTJHLENBQUMsR0FBRCxDQUEzRyxDQUFmO0FBQ0EsS0FBSUMsVUFBVSxDQUFkOztBQUhXLDRCQU1GQyxDQU5FO0FBT1ZGLFdBQVNHLE9BQVQsQ0FBaUIscUJBQWE7QUFDN0JDLGFBQVVELE9BQVYsQ0FBa0I7QUFBQSxXQUFRTixVQUFVRSxLQUFWLENBQWdCRSxPQUFoQixJQUEyQkksT0FBT0gsQ0FBMUM7QUFBQSxJQUFsQjtBQUNBRDtBQUNBLEdBSEQ7QUFQVTs7QUFNWCxNQUFLLElBQUlDLElBQUksQ0FBQyxDQUFkLEVBQWlCQSxLQUFLLENBQXRCLEVBQXlCQSxHQUF6QixFQUE4QjtBQUFBLFFBQXJCQSxDQUFxQjtBQUs3QjtBQUNELENBWkQ7O0FBY0FJLFFBQVFULFNBQVIsR0FBb0JBLFNBQXBCO0lBS01VLE07QUFDTCxpQkFBWUMsWUFBWixFQUEwQkMsTUFBMUIsRUFBa0M7QUFBQTs7QUFDakMsT0FBS0MsVUFBTCxHQUFrQixDQUFsQjtBQUNBLE9BQUtDLFNBQUwsR0FBaUIsQ0FBakI7QUFDQSxPQUFLRixNQUFMLEdBQWNBLFVBQVUsSUFBeEI7QUFDQSxPQUFLRyxRQUFMO0FBQ0EsT0FBS0MsTUFBTDtBQUNBLE9BQUtDLGFBQUwsR0FBcUIsS0FBckI7QUFDQSxPQUFLQyxNQUFMLEdBQWMsRUFBZDtBQUNBLE9BQUtDLEtBQUwsR0FBYSxHQUFiO0FBQ0EsT0FBS0MsU0FBTCxHQUFpQixDQUFqQjtBQUNBLE9BQUtDLElBQUwsR0FBWSxDQUFaO0FBQ0EsT0FBS0MsUUFBTCxHQUFnQixJQUFoQjtBQUNBLE9BQUtDLE1BQUwsR0FBYyxLQUFkO0FBQ0EsT0FBS0MsVUFBTCxHQUFrQixDQUFsQjtBQUNBLE9BQUtDLE1BQUwsR0FBYyxFQUFkO0FBQ0EsT0FBS0MsV0FBTCxHQUFtQixDQUFuQjtBQUNBLE9BQUtDLGNBQUwsR0FBc0IsRUFBdEI7O0FBRUEsTUFBSSxPQUFPaEIsWUFBUCxLQUF5QixVQUE3QixFQUF5QyxLQUFLaUIsRUFBTCxDQUFRLFdBQVIsRUFBcUJqQixZQUFyQjtBQUN6Qzs7OzsyQkFPUWtCLEksRUFBTTtBQUNkLE9BQUlDLEtBQUtDLFFBQVEsSUFBUixDQUFUO0FBQ0EsUUFBS25CLE1BQUwsR0FBY2tCLEdBQUdFLFlBQUgsQ0FBZ0JILElBQWhCLENBQWQ7QUFDQSxVQUFPLEtBQUtJLFVBQUwsRUFBUDtBQUNBOzs7a0NBT2VDLFcsRUFBYTtBQUM1QixRQUFLdEIsTUFBTCxHQUFjLElBQUl1QixVQUFKLENBQWVELFdBQWYsQ0FBZDtBQUNBLFVBQU8sS0FBS0QsVUFBTCxFQUFQO0FBQ0E7Ozs4QkFPV0csTyxFQUFTO0FBR3BCLE9BQUlDLGFBQWFDLE1BQU1DLElBQU4sQ0FBV0gsUUFBUUksS0FBUixDQUFjLEdBQWQsRUFBbUIsQ0FBbkIsQ0FBWCxDQUFqQjs7QUFHQSxPQUFJQyxLQUFLLElBQUlOLFVBQUosQ0FBZUUsV0FBV0ssTUFBMUIsQ0FBVDtBQUNBLFFBQUssSUFBSXJDLElBQUksQ0FBYixFQUFnQkEsSUFBSWdDLFdBQVdLLE1BQS9CLEVBQXVDckMsR0FBdkMsRUFBNEM7QUFDM0NvQyxPQUFHcEMsQ0FBSCxJQUFRZ0MsV0FBV00sVUFBWCxDQUFzQnRDLENBQXRCLENBQVI7QUFDQTs7QUFFRCxRQUFLTyxNQUFMLEdBQWM2QixFQUFkO0FBQ0EsVUFBTyxLQUFLUixVQUFMLEVBQVA7QUFDQTs7O2dDQU1hO0FBQ2IsVUFBTyxLQUFLckIsTUFBTCxHQUFjLEtBQUtBLE1BQUwsQ0FBWThCLE1BQTFCLEdBQW1DLENBQTFDO0FBQ0E7OzsrQkFPWTtBQUNaLE9BQUksQ0FBQyxLQUFLRSxRQUFMLEVBQUwsRUFBc0IsTUFBTSwyQ0FBTjtBQUN0QixVQUFPLEtBQUtDLFdBQUwsR0FBbUJDLFNBQW5CLEdBQStCQyxTQUEvQixHQUEyQ0MsTUFBM0MsRUFBUDtBQUNBOzs7NkJBTVU7QUFDVixVQUFPVixNQUFNVyxjQUFOLENBQXFCLEtBQUtyQyxNQUFMLENBQVlzQyxLQUFaLENBQWtCLENBQWxCLEVBQXFCLENBQXJCLENBQXJCLE1BQWtELE1BQXpEO0FBQ0E7Ozs4QkFNVzs7QUFXWCxRQUFLbEMsTUFBTCxHQUFjc0IsTUFBTWEsYUFBTixDQUFvQixLQUFLdkMsTUFBTCxDQUFZc0MsS0FBWixDQUFrQixDQUFsQixFQUFxQixFQUFyQixDQUFwQixDQUFkO0FBQ0EsVUFBTyxJQUFQO0FBQ0E7Ozs4QkFNVztBQUNYLFFBQUtoQyxNQUFMLEdBQWMsRUFBZDtBQUNBLFFBQUtOLE1BQUwsQ0FBWU4sT0FBWixDQUFvQixVQUFTOEMsSUFBVCxFQUFlQyxLQUFmLEVBQXNCO0FBQ3pDLFFBQUlmLE1BQU1XLGNBQU4sQ0FBcUIsS0FBS3JDLE1BQUwsQ0FBWXNDLEtBQVosQ0FBa0JHLEtBQWxCLEVBQXlCQSxRQUFRLENBQWpDLENBQXJCLEtBQTZELE1BQWpFLEVBQXlFO0FBQ3hFLFNBQUlDLGNBQWNoQixNQUFNYSxhQUFOLENBQW9CLEtBQUt2QyxNQUFMLENBQVlzQyxLQUFaLENBQWtCRyxRQUFRLENBQTFCLEVBQTZCQSxRQUFRLENBQXJDLENBQXBCLENBQWxCO0FBQ0EsVUFBS25DLE1BQUwsQ0FBWXFDLElBQVosQ0FBaUIsSUFBSUMsS0FBSixDQUFVLEtBQUt0QyxNQUFMLENBQVl3QixNQUF0QixFQUE4QixLQUFLOUIsTUFBTCxDQUFZc0MsS0FBWixDQUFrQkcsUUFBUSxDQUExQixFQUE2QkEsUUFBUSxDQUFSLEdBQVlDLFdBQXpDLENBQTlCLENBQWpCO0FBQ0E7QUFDRCxJQUxELEVBS0csSUFMSDs7QUFPQSxVQUFPLElBQVA7QUFDQTs7OzhCQU9XRyxXLEVBQWE7QUFDeEIsUUFBS3ZDLE1BQUwsQ0FBWXVDLGNBQWMsQ0FBMUIsRUFBNkJDLE1BQTdCO0FBQ0EsVUFBTyxJQUFQO0FBQ0E7OzsrQkFPWUQsVyxFQUFhO0FBQ3pCLFFBQUt2QyxNQUFMLENBQVl1QyxjQUFjLENBQTFCLEVBQTZCRSxPQUE3QjtBQUNBLFVBQU8sSUFBUDtBQUNBOzs7Z0NBTWE7QUFDYixRQUFLNUMsUUFBTCxHQUFnQnVCLE1BQU1hLGFBQU4sQ0FBb0IsS0FBS3ZDLE1BQUwsQ0FBWXNDLEtBQVosQ0FBa0IsRUFBbEIsRUFBc0IsRUFBdEIsQ0FBcEIsQ0FBaEI7QUFDQSxVQUFPLElBQVA7QUFDQTs7OzJCQU9RRixNLEVBQVE7QUFDaEIsT0FBSSxDQUFDLEtBQUt6QixNQUFWLEVBQWtCO0FBQ2pCLFNBQUtBLE1BQUwsR0FBYyxJQUFkO0FBQ0EsU0FBS0YsSUFBTCxHQUFZLEtBQUt1QyxjQUFMLEVBQVo7O0FBRUEsU0FBSzFDLE1BQUwsQ0FBWVosT0FBWixDQUFvQixVQUFTdUQsS0FBVCxFQUFnQjtBQUVuQyxTQUFJLENBQUNiLE1BQUQsSUFBVyxLQUFLYyxTQUFMLEVBQWYsRUFBaUM7QUFFaEMsV0FBS0Msa0JBQUwsQ0FBd0IsV0FBeEI7QUFDQSxXQUFLQyxJQUFMO0FBRUEsTUFMRCxNQUtPO0FBQ04sVUFBSUMsU0FBUUosTUFBTUssV0FBTixDQUFrQixLQUFLN0MsSUFBdkIsRUFBNkIyQixNQUE3QixDQUFaOztBQUVBLFVBQUlBLFVBQVVpQixNQUFWLElBQW1CQSxPQUFNRSxjQUFOLENBQXFCLE1BQXJCLENBQW5CLElBQW1ERixPQUFNRyxJQUFOLEtBQWUsV0FBdEUsRUFBbUY7QUFFbEYsWUFBS2pELEtBQUwsR0FBYThDLE9BQU1JLElBQW5CO0FBQ0E7O0FBRUQsVUFBSUosVUFBUyxDQUFDakIsTUFBZCxFQUFzQixLQUFLc0IsU0FBTCxDQUFlTCxNQUFmO0FBQ3RCO0FBRUQsS0FsQkQsRUFrQkcsSUFsQkg7O0FBb0JBLFFBQUksQ0FBQ2pCLE1BQUwsRUFBYSxLQUFLZSxrQkFBTCxDQUF3QixTQUF4QixFQUFtQyxFQUFDMUMsTUFBTSxLQUFLQSxJQUFaLEVBQW5DO0FBQ2IsU0FBS0UsTUFBTCxHQUFjLEtBQWQ7QUFDQTtBQUNEOzs7K0JBTVlULFMsRUFBVztBQUN2QixRQUFLQSxTQUFMLEdBQWlCQSxTQUFqQjtBQUNBOzs7eUJBTU07QUFDTixPQUFJLEtBQUt5RCxTQUFMLEVBQUosRUFBc0IsTUFBTSxvQkFBTjs7QUFHdEIsT0FBSSxDQUFDLEtBQUt6RCxTQUFWLEVBQXFCLEtBQUtBLFNBQUwsR0FBa0IsSUFBSTBELElBQUosRUFBRCxDQUFhQyxPQUFiLEVBQWpCOztBQUlyQixRQUFLeEQsYUFBTCxHQUFxQnlELFlBQVksS0FBS0MsUUFBTCxDQUFjQyxJQUFkLENBQW1CLElBQW5CLENBQVosRUFBc0MsS0FBSy9ELFVBQTNDLENBQXJCOztBQUVBLFVBQU8sSUFBUDtBQUNBOzs7MEJBTU87QUFDUGdFLGlCQUFjLEtBQUs1RCxhQUFuQjtBQUNBLFFBQUtBLGFBQUwsR0FBcUIsS0FBckI7QUFDQSxRQUFLRyxTQUFMLEdBQWlCLEtBQUtDLElBQXRCO0FBQ0EsUUFBS1AsU0FBTCxHQUFpQixDQUFqQjtBQUNBLFVBQU8sSUFBUDtBQUNBOzs7eUJBTU07QUFDTitELGlCQUFjLEtBQUs1RCxhQUFuQjtBQUNBLFFBQUtBLGFBQUwsR0FBcUIsS0FBckI7QUFDQSxRQUFLRyxTQUFMLEdBQWlCLENBQWpCO0FBQ0EsUUFBS04sU0FBTCxHQUFpQixDQUFqQjtBQUNBLFFBQUtnRSxXQUFMO0FBQ0EsVUFBTyxJQUFQO0FBQ0E7Ozs2QkFPVXpELEksRUFBTTtBQUNoQixRQUFLMkMsSUFBTDtBQUNBLFFBQUs1QyxTQUFMLEdBQWlCQyxJQUFqQjs7QUFHQSxRQUFLSCxNQUFMLENBQVlaLE9BQVosQ0FBb0IsVUFBU3VELEtBQVQsRUFBZ0I7QUFDbkNBLFVBQU1rQixtQkFBTixDQUEwQjFELElBQTFCO0FBQ0EsSUFGRDtBQUdBLFVBQU8sSUFBUDtBQUNBOzs7Z0NBT2EyRCxPLEVBQVM7QUFDdEIsT0FBSUEsVUFBVSxDQUFWLElBQWVBLFVBQVUsR0FBN0IsRUFBa0MsTUFBTSwyQ0FBTjtBQUNsQyxRQUFLQyxVQUFMLENBQWdCQyxLQUFLQyxLQUFMLENBQVdILFVBQVUsR0FBVixHQUFnQixLQUFLeEQsVUFBaEMsQ0FBaEI7QUFDQSxVQUFPLElBQVA7QUFDQTs7O2dDQU9hNEQsTyxFQUFTO0FBQ3RCLE9BQUlDLFdBQVcsS0FBS0MsV0FBTCxFQUFmO0FBQ0EsT0FBSUYsVUFBVSxDQUFWLElBQWVBLFVBQVVDLFFBQTdCLEVBQXVDLE1BQU1ELFVBQVUsbUNBQVYsR0FBZ0RDLFFBQXREO0FBQ3ZDLFFBQUtFLGFBQUwsQ0FBbUJILFVBQVVDLFFBQVYsR0FBcUIsR0FBeEM7QUFDQSxVQUFPLElBQVA7QUFDQTs7OzhCQU1XO0FBQ1gsVUFBTyxLQUFLcEUsYUFBTCxHQUFxQixDQUFyQixJQUEwQixRQUFPLEtBQUtBLGFBQVosTUFBOEIsUUFBL0Q7QUFDQTs7OzJCQU1RO0FBRVIsUUFBSzZELFdBQUw7QUFDQSxVQUFPLENBQUMsS0FBS2hCLFNBQUwsRUFBUjtBQUEwQixTQUFLYSxRQUFMLENBQWMsSUFBZDtBQUExQixJQUNBLEtBQUtsRCxNQUFMLEdBQWMsS0FBSytELFNBQUwsRUFBZDtBQUNBLFFBQUs5RCxXQUFMLEdBQW1CLEtBQUsrRCxjQUFMLEVBQW5CO0FBQ0EsUUFBS2pFLFVBQUwsR0FBa0IsS0FBS2tFLGFBQUwsRUFBbEI7QUFDQSxRQUFLdEUsU0FBTCxHQUFpQixDQUFqQjtBQUNBLFFBQUtOLFNBQUwsR0FBaUIsQ0FBakI7O0FBR0EsUUFBS2dFLFdBQUw7O0FBSUEsUUFBS2Ysa0JBQUwsQ0FBd0IsWUFBeEIsRUFBc0MsSUFBdEM7QUFDQSxVQUFPLElBQVA7QUFDQTs7O2dDQU1hO0FBQ2IsUUFBSzdDLE1BQUwsQ0FBWVosT0FBWixDQUFvQjtBQUFBLFdBQVN1RCxNQUFNOEIsS0FBTixFQUFUO0FBQUEsSUFBcEI7QUFDQSxVQUFPLElBQVA7QUFDQTs7OzhCQU1XO0FBQ1gsVUFBTyxLQUFLekUsTUFBTCxDQUFZMEUsR0FBWixDQUFnQjtBQUFBLFdBQVMvQixNQUFNcEMsTUFBZjtBQUFBLElBQWhCLENBQVA7QUFDQTs7O2tDQU1lO0FBQ2YsVUFBT3lELEtBQUtXLEdBQUwsQ0FBU0MsS0FBVCxDQUFlLElBQWYsRUFBcUIsS0FBSzVFLE1BQUwsQ0FBWTBFLEdBQVosQ0FBZ0I7QUFBQSxXQUFTL0IsTUFBTWtDLEtBQWY7QUFBQSxJQUFoQixDQUFyQixDQUFQO0FBQ0E7OzttQ0FNZ0I7QUFDaEIsVUFBTyxLQUFLN0UsTUFBTCxDQUFZOEUsTUFBWixDQUFtQixVQUFDQyxDQUFELEVBQUlDLENBQUosRUFBVTtBQUFDLFdBQU8sRUFBQ3pFLFFBQVEsRUFBQ2lCLFFBQVF1RCxFQUFFeEUsTUFBRixDQUFTaUIsTUFBVCxHQUFrQndELEVBQUV6RSxNQUFGLENBQVNpQixNQUFwQyxFQUFULEVBQVA7QUFBNkQsSUFBM0YsRUFBNkYsRUFBQ2pCLFFBQVEsRUFBQ2lCLFFBQVEsQ0FBVCxFQUFULEVBQTdGLEVBQW9IakIsTUFBcEgsQ0FBMkhpQixNQUFsSTtBQUNBOzs7Z0NBTWE7QUFDYixVQUFPLEtBQUtsQixVQUFMLEdBQWtCLEtBQUtULFFBQXZCLEdBQWtDLEtBQUtJLEtBQXZDLEdBQStDLEVBQXREO0FBQ0E7Ozt5Q0FNc0I7QUFDdEIsVUFBTytELEtBQUtDLEtBQUwsQ0FBVyxDQUFDLEtBQUszRCxVQUFMLEdBQWtCLEtBQUtILElBQXhCLElBQWdDLEtBQUtOLFFBQXJDLEdBQWdELEtBQUtJLEtBQXJELEdBQTZELEVBQXhFLENBQVA7QUFDQTs7OzRDQU15QjtBQUN6QixVQUFPK0QsS0FBS0MsS0FBTCxDQUFXLEtBQUtnQixvQkFBTCxLQUE4QixLQUFLYixXQUFMLEVBQTlCLEdBQW1ELEdBQTlELENBQVA7QUFDQTs7O21DQU1nQjtBQUVoQixVQUFPLEtBQUssS0FBS3BFLE1BQUwsQ0FBWXdCLE1BQVosR0FBcUIsQ0FBMUIsR0FBOEIsS0FBS3hCLE1BQUwsQ0FBWThFLE1BQVosQ0FBbUIsVUFBQ0MsQ0FBRCxFQUFJQyxDQUFKLEVBQVU7QUFBQyxXQUFPLEVBQUNFLFNBQVNILEVBQUVHLE9BQUYsR0FBWUYsRUFBRUUsT0FBeEIsRUFBUDtBQUF3QyxJQUF0RSxFQUF3RSxFQUFDQSxTQUFTLENBQVYsRUFBeEUsRUFBc0ZBLE9BQTNIO0FBQ0E7OztpQ0FNYztBQUNkLFVBQU8sS0FBS2xGLE1BQUwsQ0FBWThFLE1BQVosQ0FBbUIsVUFBQ0MsQ0FBRCxFQUFJQyxDQUFKLEVBQVU7QUFBQyxXQUFPLEVBQUNHLFlBQVlKLEVBQUVJLFVBQUYsR0FBZUgsRUFBRUcsVUFBOUIsRUFBUDtBQUFpRCxJQUEvRSxFQUFpRixFQUFDQSxZQUFZLENBQWIsRUFBakYsRUFBa0dBLFVBQXpHO0FBQ0E7Ozs4QkFTVztBQUNYLE9BQUksS0FBSzlCLFNBQUwsRUFBSixFQUFzQjtBQUNyQixXQUFPLEtBQUsrQixZQUFMLE1BQXVCLEtBQUs1RSxXQUFuQztBQUNBOztBQUVELFVBQU8sS0FBSzZFLGNBQUwsTUFBeUIsS0FBSzNGLE1BQUwsQ0FBWThCLE1BQTVDO0FBQ0E7OzttQ0FNZ0I7QUFDaEIsVUFBT3dDLEtBQUtDLEtBQUwsQ0FBVyxDQUFFLElBQUlYLElBQUosRUFBRCxDQUFhQyxPQUFiLEtBQXlCLEtBQUszRCxTQUEvQixJQUE0QyxJQUE1QyxJQUFvRCxLQUFLQyxRQUFMLElBQWlCLEtBQUtJLEtBQUwsR0FBYSxFQUE5QixDQUFwRCxDQUFYLElBQXFHLEtBQUtDLFNBQWpIO0FBQ0E7Ozs0QkFPUzZDLEssRUFBTztBQUNoQixRQUFLRixrQkFBTCxDQUF3QixXQUF4QixFQUFxQ0UsS0FBckM7QUFDQSxVQUFPLElBQVA7QUFDQTs7O3FCQVFFdUMsVyxFQUFhQyxFLEVBQUk7QUFDbkIsT0FBSSxDQUFDLEtBQUs5RSxjQUFMLENBQW9Cd0MsY0FBcEIsQ0FBbUNxQyxXQUFuQyxDQUFMLEVBQXNELEtBQUs3RSxjQUFMLENBQW9CNkUsV0FBcEIsSUFBbUMsRUFBbkM7QUFDdEQsUUFBSzdFLGNBQUwsQ0FBb0I2RSxXQUFwQixFQUFpQ2pELElBQWpDLENBQXNDa0QsRUFBdEM7QUFDQSxVQUFPLElBQVA7QUFDQTs7O3FDQVFrQkQsVyxFQUFhbkMsSSxFQUFNO0FBQ3JDLE9BQUksS0FBSzFDLGNBQUwsQ0FBb0J3QyxjQUFwQixDQUFtQ3FDLFdBQW5DLENBQUosRUFBcUQsS0FBSzdFLGNBQUwsQ0FBb0I2RSxXQUFwQixFQUFpQ2xHLE9BQWpDLENBQXlDO0FBQUEsV0FBTW1HLEdBQUdwQyxRQUFRLEVBQVgsQ0FBTjtBQUFBLElBQXpDO0FBQ3JELFVBQU8sSUFBUDtBQUNBOzs7Ozs7QUFJRjVELFFBQVFDLE1BQVIsR0FBaUJBLE1BQWpCOztJQUlNOEMsSztBQUNMLGdCQUFZSCxLQUFaLEVBQW1CZ0IsSUFBbkIsRUFBeUI7QUFBQTs7QUFDeEIsT0FBS3FDLE9BQUwsR0FBZSxJQUFmO0FBQ0EsT0FBS0wsVUFBTCxHQUFrQixDQUFsQjtBQUNBLE9BQUtELE9BQUwsR0FBZSxDQUFmO0FBQ0EsT0FBSzlFLFFBQUwsR0FBZ0IsQ0FBaEI7QUFDQSxPQUFLcUYsVUFBTCxHQUFrQixJQUFsQjtBQUNBLE9BQUt0RCxLQUFMLEdBQWFBLEtBQWI7QUFDQSxPQUFLZ0IsSUFBTCxHQUFZQSxJQUFaO0FBQ0EsT0FBSzBCLEtBQUwsR0FBYSxDQUFiO0FBQ0EsT0FBS2EsWUFBTCxHQUFvQixDQUFwQjtBQUNBLE9BQUtuRixNQUFMLEdBQWMsRUFBZDtBQUNBOzs7OzBCQU1PO0FBQ1AsUUFBS2lGLE9BQUwsR0FBZSxJQUFmO0FBQ0EsUUFBS0wsVUFBTCxHQUFrQixDQUFsQjtBQUNBLFFBQUtELE9BQUwsR0FBZSxDQUFmO0FBQ0EsUUFBSzlFLFFBQUwsR0FBZ0IsQ0FBaEI7QUFDQSxRQUFLcUYsVUFBTCxHQUFrQixJQUFsQjtBQUNBLFFBQUtaLEtBQUwsR0FBYSxDQUFiO0FBQ0EsUUFBS2EsWUFBTCxHQUFvQixDQUFwQjtBQUNBLFVBQU8sSUFBUDtBQUNBOzs7MkJBTVE7QUFDUixRQUFLRixPQUFMLEdBQWUsSUFBZjtBQUNBLFVBQU8sSUFBUDtBQUNBOzs7NEJBTVM7QUFDVCxRQUFLQSxPQUFMLEdBQWUsS0FBZjtBQUNBLFVBQU8sSUFBUDtBQUNBOzs7c0NBT21CckYsSSxFQUFNO0FBQ3pCQSxVQUFPQSxRQUFRLENBQWY7O0FBRUEsUUFBSyxJQUFJaEIsQ0FBVCxJQUFjLEtBQUtvQixNQUFuQixFQUEyQjtBQUMxQixRQUFJLEtBQUtBLE1BQUwsQ0FBWXBCLENBQVosRUFBZWdCLElBQWYsSUFBdUJBLElBQTNCLEVBQWlDO0FBQ2hDLFVBQUtnRixVQUFMLEdBQWtCaEcsQ0FBbEI7QUFDQSxZQUFPLElBQVA7QUFDQTtBQUNEO0FBQ0Q7OzttQ0FNZ0I7QUFDaEIsVUFBTyxLQUFLZ0UsSUFBTCxDQUFVLEtBQUsrQixPQUFmLENBQVA7QUFDQTs7O3NDQU1tQjtBQU1oQixPQUFJUyxjQUFjLEtBQUtDLGNBQUwsRUFBbEI7QUFDQSxPQUFJQyxZQUFZLENBQWhCOztBQUVILFVBQU9GLGVBQWUsR0FBdEIsRUFBMkI7QUFDMUJBLGtCQUFjLEtBQUt4QyxJQUFMLENBQVUsS0FBSytCLE9BQUwsR0FBZVcsU0FBekIsQ0FBZDtBQUNBQTtBQUNBOztBQUVELFVBQU9BLFNBQVA7QUFDQTs7OzZCQU1VO0FBQ1YsVUFBT3pFLE1BQU0wRSxVQUFOLENBQWlCLEtBQUszQyxJQUFMLENBQVVuQixLQUFWLENBQWdCLEtBQUtrRCxPQUFyQixFQUE4QixLQUFLQSxPQUFMLEdBQWUsS0FBS2EsaUJBQUwsRUFBN0MsQ0FBakIsQ0FBUDtBQUNBOzs7OEJBT1dDLFcsRUFBYWxFLE0sRUFBUTtBQUNoQ0EsWUFBU0EsVUFBVSxLQUFuQjs7QUFFQSxPQUFJQSxNQUFKLEVBQVk7QUFDWCxRQUFJbUUsZUFBZUQsY0FBYyxLQUFLNUYsUUFBdEM7QUFDQSxRQUFJeUUsUUFBUSxLQUFLcUIsUUFBTCxFQUFaO0FBQ0EsUUFBSUMsYUFBYUYsZ0JBQWdCcEIsS0FBakM7O0FBRUEsUUFBSSxLQUFLSyxPQUFMLEdBQWUsS0FBSy9CLElBQUwsQ0FBVTNCLE1BQXpCLEtBQW9DTSxVQUFVcUUsVUFBOUMsQ0FBSixFQUErRDtBQUM5RCxTQUFJcEQsVUFBUSxLQUFLcUQsVUFBTCxFQUFaO0FBQ0EsU0FBSSxLQUFLWixPQUFULEVBQWtCLE9BQU96QyxPQUFQO0FBRWxCO0FBRUQsSUFYRCxNQVdPO0FBRU4sUUFBSSxLQUFLeEMsTUFBTCxDQUFZLEtBQUs0RSxVQUFqQixLQUFnQyxLQUFLNUUsTUFBTCxDQUFZLEtBQUs0RSxVQUFqQixFQUE2QmhGLElBQTdCLElBQXFDNkYsV0FBekUsRUFBc0Y7QUFDckYsVUFBS2IsVUFBTDtBQUNBLFNBQUksS0FBS0ssT0FBVCxFQUFrQixPQUFPLEtBQUtqRixNQUFMLENBQVksS0FBSzRFLFVBQUwsR0FBa0IsQ0FBOUIsQ0FBUDtBQUNsQjtBQUNEOztBQUVELFVBQU8sSUFBUDtBQUNBOzs7Z0NBT2FrQixlLEVBQWlCO0FBQzlCLE9BQUlWLGNBQWMsS0FBS1QsT0FBdkI7QUFDQSxPQUFJVyxZQUFZLENBQWhCO0FBQ0EsT0FBSXJFLFNBQVNKLE1BQU0wRSxVQUFOLENBQWlCLEtBQUszQyxJQUFMLENBQVVuQixLQUFWLENBQWdCcUUsa0JBQWtCLENBQWxDLEVBQXFDQSxrQkFBa0IsQ0FBbEIsR0FBc0JSLFNBQTNELENBQWpCLENBQWI7QUFDQSxPQUFJUyxlQUFlOUUsTUFBbkI7O0FBRUEsVUFBT0osTUFBTVcsY0FBTixDQUFxQixLQUFLb0IsSUFBTCxDQUFVbkIsS0FBVixDQUFnQnFFLGtCQUFrQlIsU0FBbEIsR0FBOEIsQ0FBOUMsRUFBaURRLGtCQUFrQlIsU0FBbEIsR0FBOEJyRSxNQUE5QixHQUF1QyxDQUF4RixDQUFyQixDQUFQO0FBQ0E7OzsrQkFNWTtBQUNaLE9BQUk2RSxrQkFBa0IsS0FBS25CLE9BQUwsR0FBZSxLQUFLYSxpQkFBTCxFQUFyQztBQUNBLE9BQUlRLFlBQVksRUFBaEI7QUFDQSxPQUFJQyxpQkFBaUIsS0FBS1QsaUJBQUwsRUFBckI7QUFDQVEsYUFBVTVELEtBQVYsR0FBa0IsS0FBS1IsS0FBTCxHQUFhLENBQS9CO0FBQ0FvRSxhQUFVMUIsS0FBVixHQUFrQixLQUFLcUIsUUFBTCxFQUFsQjtBQUNBLFFBQUs5RixRQUFMLEdBQWdCLEtBQUtBLFFBQUwsR0FBZ0JtRyxVQUFVMUIsS0FBMUM7QUFDQSxRQUFLYSxZQUFMLElBQXFCYSxVQUFVMUIsS0FBL0I7QUFDQTBCLGFBQVVwRyxJQUFWLEdBQWlCLEtBQUt1RixZQUF0QjtBQUNBYSxhQUFVRSxTQUFWLEdBQXNCLEtBQUt2QixPQUEzQjs7QUFHQSxPQUFJLEtBQUsvQixJQUFMLENBQVVrRCxlQUFWLEtBQThCLElBQWxDLEVBQXdDOztBQU92QyxZQUFPLEtBQUtsRCxJQUFMLENBQVVrRCxrQkFBa0IsQ0FBNUIsQ0FBUDtBQUNDLFVBQUssSUFBTDtBQUNDRSxnQkFBVXJELElBQVYsR0FBaUIsaUJBQWpCO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ3FELGdCQUFVckQsSUFBVixHQUFpQixZQUFqQjtBQUNBcUQsZ0JBQVVHLE1BQVYsR0FBbUIsS0FBS0MsYUFBTCxDQUFtQk4sZUFBbkIsQ0FBbkI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDRSxnQkFBVXJELElBQVYsR0FBaUIsa0JBQWpCO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ3FELGdCQUFVckQsSUFBVixHQUFpQixxQkFBakI7QUFDQXFELGdCQUFVRyxNQUFWLEdBQW1CLEtBQUtDLGFBQUwsQ0FBbUJOLGVBQW5CLENBQW5CO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ0UsZ0JBQVVyRCxJQUFWLEdBQWlCLGlCQUFqQjtBQUNBcUQsZ0JBQVVHLE1BQVYsR0FBbUIsS0FBS0MsYUFBTCxDQUFtQk4sZUFBbkIsQ0FBbkI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDRSxnQkFBVXJELElBQVYsR0FBaUIsT0FBakI7QUFDQXFELGdCQUFVRyxNQUFWLEdBQW1CLEtBQUtDLGFBQUwsQ0FBbUJOLGVBQW5CLENBQW5CO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ0UsZ0JBQVVyRCxJQUFWLEdBQWlCLFFBQWpCO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ3FELGdCQUFVckQsSUFBVixHQUFpQixXQUFqQjtBQUNBcUQsZ0JBQVVHLE1BQVYsR0FBbUIsS0FBS0MsYUFBTCxDQUFtQk4sZUFBbkIsQ0FBbkI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDRSxnQkFBVXJELElBQVYsR0FBaUIsYUFBakI7QUFDQXFELGdCQUFVRyxNQUFWLEdBQW1CLEtBQUtDLGFBQUwsQ0FBbUJOLGVBQW5CLENBQW5CO0FBQ0E7QUFDRCxVQUFLLElBQUw7QUFDQ0UsZ0JBQVVyRCxJQUFWLEdBQWlCLHFCQUFqQjtBQUNBO0FBQ0QsVUFBSyxJQUFMO0FBQ0NxRCxnQkFBVXJELElBQVYsR0FBaUIsV0FBakI7QUFDQXFELGdCQUFVcEQsSUFBVixHQUFpQi9CLE1BQU1hLGFBQU4sQ0FBb0IsQ0FBQyxLQUFLa0IsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLENBQUQsQ0FBcEIsQ0FBakI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDRSxnQkFBVXJELElBQVYsR0FBaUIsY0FBakI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDcUQsZ0JBQVVyRCxJQUFWLEdBQWlCLFdBQWpCO0FBQ0FxRCxnQkFBVXBELElBQVYsR0FBaUJhLEtBQUtDLEtBQUwsQ0FBVyxXQUFXN0MsTUFBTWEsYUFBTixDQUFvQixLQUFLa0IsSUFBTCxDQUFVbkIsS0FBVixDQUFnQnFFLGtCQUFrQixDQUFsQyxFQUFxQ0Esa0JBQWtCLENBQXZELENBQXBCLENBQXRCLENBQWpCO0FBQ0EsV0FBS3BHLEtBQUwsR0FBYXNHLFVBQVVwRCxJQUF2QjtBQUNBO0FBQ0QsVUFBSyxJQUFMO0FBQ0NvRCxnQkFBVXJELElBQVYsR0FBaUIsY0FBakI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDcUQsZ0JBQVVyRCxJQUFWLEdBQWlCLGdCQUFqQjtBQUNBO0FBQ0QsVUFBSyxJQUFMO0FBQ0NxRCxnQkFBVXJELElBQVYsR0FBaUIsZUFBakI7QUFDQTtBQUNELFVBQUssSUFBTDtBQUNDcUQsZ0JBQVVyRCxJQUFWLEdBQWlCLCtCQUFqQjtBQUNBO0FBQ0Q7QUFDQ3FELGdCQUFVckQsSUFBVixHQUFpQixjQUFjLEtBQUtDLElBQUwsQ0FBVWtELGtCQUFrQixDQUE1QixFQUErQk8sUUFBL0IsQ0FBd0MsRUFBeEMsQ0FBL0I7QUFDQTtBQS9ERjs7QUFrRUEsUUFBSXBGLFNBQVMsS0FBSzJCLElBQUwsQ0FBVSxLQUFLK0IsT0FBTCxHQUFlc0IsY0FBZixHQUFnQyxDQUExQyxDQUFiOzs7QUFHQSxTQUFLdEIsT0FBTCxJQUFnQnNCLGlCQUFpQixDQUFqQixHQUFxQmhGLE1BQXJDO0FBRUEsSUE5RUQsTUE4RU8sSUFBRyxLQUFLMkIsSUFBTCxDQUFVa0QsZUFBVixLQUE4QixJQUFqQyxFQUF1QztBQUU3Q0UsY0FBVXJELElBQVYsR0FBaUIsT0FBakI7QUFDQSxRQUFJMUIsU0FBUyxLQUFLMkIsSUFBTCxDQUFVLEtBQUsrQixPQUFMLEdBQWVzQixjQUFmLEdBQWdDLENBQTFDLENBQWI7QUFDQSxTQUFLdEIsT0FBTCxJQUFnQnNCLGlCQUFpQixDQUFqQixHQUFxQmhGLE1BQXJDO0FBRUEsSUFOTSxNQU1BO0FBRU4sUUFBSSxLQUFLMkIsSUFBTCxDQUFVa0QsZUFBVixJQUE2QixJQUFqQyxFQUF1QztBQUV0Q0UsZUFBVU0sT0FBVixHQUFvQixJQUFwQjtBQUNBTixlQUFVTyxVQUFWLEdBQXVCLEtBQUszRCxJQUFMLENBQVVrRCxlQUFWLENBQXZCO0FBQ0FFLGVBQVVRLFFBQVYsR0FBcUJqSSxVQUFVRSxLQUFWLENBQWdCLEtBQUttRSxJQUFMLENBQVVrRCxlQUFWLENBQWhCLENBQXJCO0FBQ0FFLGVBQVVTLFFBQVYsR0FBcUIsS0FBSzdELElBQUwsQ0FBVWtELGtCQUFrQixDQUE1QixDQUFyQjs7QUFFQSxTQUFJLEtBQUtaLFVBQUwsSUFBbUIsSUFBdkIsRUFBNkI7QUFDNUJjLGdCQUFVckQsSUFBVixHQUFpQixVQUFqQjtBQUNBcUQsZ0JBQVVVLE9BQVYsR0FBb0IsS0FBS3hCLFVBQUwsR0FBa0IsSUFBbEIsR0FBeUIsQ0FBN0M7QUFFQSxNQUpELE1BSU8sSUFBSSxLQUFLQSxVQUFMLElBQW1CLElBQXZCLEVBQTZCO0FBQ25DYyxnQkFBVXJELElBQVYsR0FBaUIsU0FBakI7QUFDQXFELGdCQUFVVSxPQUFWLEdBQW9CLEtBQUt4QixVQUFMLEdBQWtCLElBQWxCLEdBQXlCLENBQTdDO0FBQ0E7O0FBRUQsVUFBS1AsT0FBTCxJQUFnQnNCLGlCQUFpQixDQUFqQztBQUVBLEtBbEJELE1Ba0JPO0FBQ04sVUFBS2YsVUFBTCxHQUFrQixLQUFLdEMsSUFBTCxDQUFVa0QsZUFBVixDQUFsQjs7QUFFQSxTQUFJLEtBQUtsRCxJQUFMLENBQVVrRCxlQUFWLEtBQThCLElBQWxDLEVBQXdDO0FBRXZDRSxnQkFBVXJELElBQVYsR0FBaUIsVUFBakI7QUFDQXFELGdCQUFVVSxPQUFWLEdBQW9CLEtBQUt4QixVQUFMLEdBQWtCLElBQWxCLEdBQXlCLENBQTdDO0FBQ0FjLGdCQUFVTyxVQUFWLEdBQXVCLEtBQUszRCxJQUFMLENBQVVrRCxrQkFBa0IsQ0FBNUIsQ0FBdkI7QUFDQUUsZ0JBQVVRLFFBQVYsR0FBcUJqSSxVQUFVRSxLQUFWLENBQWdCLEtBQUttRSxJQUFMLENBQVVrRCxrQkFBa0IsQ0FBNUIsQ0FBaEIsQ0FBckI7QUFDQUUsZ0JBQVVTLFFBQVYsR0FBcUJoRCxLQUFLQyxLQUFMLENBQVcsS0FBS2QsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLElBQWlDLEdBQWpDLEdBQXVDLEdBQWxELENBQXJCO0FBQ0EsV0FBS25CLE9BQUwsSUFBZ0JzQixpQkFBaUIsQ0FBakM7QUFFQSxNQVRELE1BU08sSUFBSSxLQUFLckQsSUFBTCxDQUFVa0QsZUFBVixLQUE4QixJQUFsQyxFQUF3QztBQUU5Q0UsZ0JBQVVyRCxJQUFWLEdBQWlCLFNBQWpCO0FBQ0FxRCxnQkFBVVUsT0FBVixHQUFvQixLQUFLeEIsVUFBTCxHQUFrQixJQUFsQixHQUF5QixDQUE3QztBQUNBYyxnQkFBVU8sVUFBVixHQUF1QixLQUFLM0QsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLENBQXZCO0FBQ0FFLGdCQUFVUSxRQUFWLEdBQXFCakksVUFBVUUsS0FBVixDQUFnQixLQUFLbUUsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLENBQWhCLENBQXJCO0FBQ0FFLGdCQUFVUyxRQUFWLEdBQXFCaEQsS0FBS0MsS0FBTCxDQUFXLEtBQUtkLElBQUwsQ0FBVWtELGtCQUFrQixDQUE1QixJQUFpQyxHQUFqQyxHQUF1QyxHQUFsRCxDQUFyQjtBQUNBLFdBQUtuQixPQUFMLElBQWdCc0IsaUJBQWlCLENBQWpDO0FBRUEsTUFUTSxNQVNBLElBQUksS0FBS3JELElBQUwsQ0FBVWtELGVBQVYsS0FBOEIsSUFBbEMsRUFBd0M7QUFFOUNFLGdCQUFVckQsSUFBVixHQUFpQix5QkFBakI7QUFDQXFELGdCQUFVVSxPQUFWLEdBQW9CLEtBQUt4QixVQUFMLEdBQWtCLElBQWxCLEdBQXlCLENBQTdDO0FBQ0FjLGdCQUFVakgsSUFBVixHQUFpQlIsVUFBVUUsS0FBVixDQUFnQixLQUFLbUUsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLENBQWhCLENBQWpCO0FBQ0FFLGdCQUFVVyxRQUFWLEdBQXFCbkUsTUFBTSxDQUFOLENBQXJCO0FBQ0EsV0FBS21DLE9BQUwsSUFBZ0JzQixpQkFBaUIsQ0FBakM7QUFFQSxNQVJNLE1BUUEsSUFBSSxLQUFLckQsSUFBTCxDQUFVa0QsZUFBVixLQUE4QixJQUFsQyxFQUF3QztBQUU5Q0UsZ0JBQVVyRCxJQUFWLEdBQWlCLG1CQUFqQjtBQUNBcUQsZ0JBQVVVLE9BQVYsR0FBb0IsS0FBS3hCLFVBQUwsR0FBa0IsSUFBbEIsR0FBeUIsQ0FBN0M7QUFDQWMsZ0JBQVVZLE1BQVYsR0FBbUIsS0FBS2hFLElBQUwsQ0FBVWtELGtCQUFrQixDQUE1QixDQUFuQjtBQUNBRSxnQkFBVWEsS0FBVixHQUFrQixLQUFLakUsSUFBTCxDQUFVa0Qsa0JBQWtCLENBQTVCLENBQWxCO0FBQ0EsV0FBS25CLE9BQUwsSUFBZ0JzQixpQkFBaUIsQ0FBakM7QUFFQSxNQVJNLE1BUUEsSUFBSSxLQUFLckQsSUFBTCxDQUFVa0QsZUFBVixLQUE4QixJQUFsQyxFQUF3QztBQUU5Q0UsZ0JBQVVyRCxJQUFWLEdBQWlCLGdCQUFqQjtBQUNBcUQsZ0JBQVVVLE9BQVYsR0FBb0IsS0FBS3hCLFVBQUwsR0FBa0IsSUFBbEIsR0FBeUIsQ0FBN0M7QUFDQSxXQUFLUCxPQUFMLElBQWdCc0IsaUJBQWlCLENBQWpDO0FBRUEsTUFOTSxNQU1BLElBQUksS0FBS3JELElBQUwsQ0FBVWtELGVBQVYsS0FBOEIsSUFBbEMsRUFBd0M7QUFFOUNFLGdCQUFVckQsSUFBVixHQUFpQixzQkFBakI7QUFDQXFELGdCQUFVVSxPQUFWLEdBQW9CLEtBQUt4QixVQUFMLEdBQWtCLElBQWxCLEdBQXlCLENBQTdDO0FBQ0EsV0FBS1AsT0FBTCxJQUFnQnNCLGlCQUFpQixDQUFqQztBQUVBLE1BTk0sTUFNQSxJQUFJLEtBQUtyRCxJQUFMLENBQVVrRCxlQUFWLEtBQThCLElBQWxDLEVBQXdDO0FBRTlDRSxnQkFBVXJELElBQVYsR0FBaUIsWUFBakI7QUFDQXFELGdCQUFVVSxPQUFWLEdBQW9CLEtBQUt4QixVQUFMLEdBQWtCLElBQWxCLEdBQXlCLENBQTdDO0FBQ0EsV0FBS1AsT0FBTCxJQUFnQnNCLGlCQUFpQixDQUFqQztBQUVBLE1BTk0sTUFNQTtBQUNORCxnQkFBVXJELElBQVYsR0FBaUIsd0JBQXdCLEtBQUtnQyxPQUFMLENBQWEwQixRQUFiLEVBQXhCLEdBQWtELEdBQWxELEdBQXlEUCxnQkFBZ0JPLFFBQWhCLEVBQXpELEdBQXNGLEdBQXRGLEdBQTRGLEtBQUt6RCxJQUFMLENBQVUzQixNQUF2SDtBQUNBO0FBQ0Q7QUFDRDs7QUFFRCxRQUFLcUQsS0FBTCxJQUFjMEIsVUFBVTFCLEtBQXhCO0FBQ0EsUUFBS3RFLE1BQUwsQ0FBWThCLElBQVosQ0FBaUJrRSxTQUFqQjs7QUFFQSxVQUFPQSxTQUFQO0FBQ0E7OzsrQkFNWTtBQUNaLE9BQUksS0FBS3BELElBQUwsQ0FBVSxLQUFLK0IsT0FBTCxHQUFlLENBQXpCLEtBQStCLElBQS9CLElBQXVDLEtBQUsvQixJQUFMLENBQVUsS0FBSytCLE9BQUwsR0FBZSxDQUF6QixLQUErQixJQUF0RSxJQUE4RSxLQUFLL0IsSUFBTCxDQUFVLEtBQUsrQixPQUFMLEdBQWUsQ0FBekIsS0FBK0IsSUFBakgsRUFBdUg7QUFDdEgsV0FBTyxJQUFQO0FBQ0E7O0FBRUQsVUFBTyxLQUFQO0FBQ0E7Ozs7OztJQUtJOUQsSzs7Ozs7Ozs0QkFPWWMsSSxFQUFNO0FBRXRCLFVBQU8sQ0FBQyxNQUFNQSxLQUFLMEUsUUFBTCxDQUFjLEVBQWQsQ0FBUCxFQUEwQjVFLEtBQTFCLENBQWdDLENBQUMsQ0FBakMsQ0FBUDtBQUNBOzs7NkJBT2lCcUYsUyxFQUFXO0FBQzVCLE9BQUlDLE1BQU0sRUFBVjtBQUNBRCxhQUFVakksT0FBVixDQUFrQjtBQUFBLFdBQVFrSSxJQUFJakYsSUFBSixDQUFTakIsTUFBTW1HLFNBQU4sQ0FBZ0JyRixJQUFoQixDQUFULENBQVI7QUFBQSxJQUFsQjtBQUNBLFVBQU9vRixJQUFJRSxJQUFKLENBQVMsRUFBVCxDQUFQO0FBQ0E7Ozs4QkFPa0JDLFMsRUFBVztBQUM3QixVQUFPQyxTQUFTRCxTQUFULEVBQW9CLEVBQXBCLENBQVA7QUFDQTs7O2dDQU9vQkosUyxFQUFXO0FBQy9CLFVBQU9qRyxNQUFNdUcsV0FBTixDQUFrQnZHLE1BQU13RyxVQUFOLENBQWlCUCxTQUFqQixDQUFsQixDQUFQO0FBQ0E7OztpQ0FPcUJBLFMsRUFBVztBQUNoQyxPQUFJUSxVQUFVLEVBQWQ7QUFDQVIsYUFBVWpJLE9BQVYsQ0FBa0I7QUFBQSxXQUFReUksUUFBUXhGLElBQVIsQ0FBYXlGLE9BQU9DLFlBQVAsQ0FBb0I3RixJQUFwQixDQUFiLENBQVI7QUFBQSxJQUFsQjtBQUNBLFVBQU8yRixRQUFRTCxJQUFSLENBQWEsRUFBYixDQUFQO0FBQ0E7Ozs4QkFPa0JRLEcsRUFBSztBQUNwQixVQUFPLENBQUNBLFFBQVEsQ0FBVCxFQUFZcEIsUUFBWixDQUFxQixDQUFyQixDQUFQO0FBQ0g7Ozs2QkFPaUJTLFMsRUFBVztBQUM1QixPQUFJWSxTQUFTLENBQWI7QUFDQVosYUFBVWpJLE9BQVYsQ0FBa0Isa0JBQVU7QUFDM0IsUUFBSTRGLElBQUltQyxNQUFSO0FBQ0EsUUFBSW5DLElBQUksSUFBUixFQUFjO0FBQ2JpRCxlQUFXakQsSUFBSSxJQUFmO0FBQ0FpRCxnQkFBVyxDQUFYO0FBQ0EsS0FIRCxNQUdPO0FBRU5BLGVBQVVqRCxDQUFWO0FBQ0E7QUFDRCxJQVREOztBQVdBLFVBQU9pRCxNQUFQO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Y0FPV3ZCLE0sRUFBUTtBQUNuQixPQUFJLE9BQU9yRixJQUFQLEtBQWdCLFVBQXBCLEVBQWdDLE9BQU9BLEtBQUtxRixNQUFMLENBQVA7QUFDaEMsVUFBTyxJQUFJd0IsTUFBSixDQUFXeEIsTUFBWCxFQUFtQixRQUFuQixFQUE2QkUsUUFBN0IsQ0FBc0MsUUFBdEMsQ0FBUDtBQUNBLEc7Ozs7OztBQUdGckgsUUFBUTZCLEtBQVIsR0FBZ0JBLEtBQWhCIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb25zdGFudHMgdXNlZCBpbiBwbGF5ZXIuXG4gKi9cbnZhciBDb25zdGFudHMgPSB7XG5cdFZFUlNJT046ICcxLjEuNCcsXG5cdE5PVEVTOiBbXVxufTtcblxuKGZ1bmN0aW9uKCkge1xuXHQvLyBCdWlsZHMgbm90ZXMgb2JqZWN0IGZvciByZWZlcmVuY2UgYWdhaW5zdCBiaW5hcnkgdmFsdWVzLlxuXHR2YXIgYWxsTm90ZXMgPSBbWydDJ10sIFsnQyMnLCdEYiddLCBbJ0QnXSwgWydEIycsJ0ViJ10sIFsnRSddLFsnRiddLCBbJ0YjJywnR2InXSwgWydHJ10sIFsnRyMnLCdBYiddLCBbJ0EnXSwgWydBIycsJ0JiJ10sIFsnQiddXTtcblx0dmFyIGNvdW50ZXIgPSAwO1xuXG5cdC8vIEFsbCBhdmFpbGFibGUgb2N0YXZlcy5cblx0Zm9yIChsZXQgaSA9IC0xOyBpIDw9IDk7IGkrKykge1xuXHRcdGFsbE5vdGVzLmZvckVhY2gobm90ZUdyb3VwID0+IHtcblx0XHRcdG5vdGVHcm91cC5mb3JFYWNoKG5vdGUgPT4gQ29uc3RhbnRzLk5PVEVTW2NvdW50ZXJdID0gbm90ZSArIGkpO1xuXHRcdFx0Y291bnRlciArKztcblx0XHR9KTtcblx0fVxufSkoKTtcblxuZXhwb3J0cy5Db25zdGFudHMgPSBDb25zdGFudHM7LyoqXG4gKiBNYWluIHBsYXllciBjbGFzcy4gIENvbnRhaW5zIG1ldGhvZHMgdG8gbG9hZCBmaWxlcywgc3RhcnQsIHN0b3AuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSAtIENhbGxiYWNrIHRvIGZpcmUgZm9yIGVhY2ggTUlESSBldmVudC4gIENhbiBhbHNvIGJlIGFkZGVkIHdpdGggb24oJ21pZGlFdmVudCcsIGZuKVxuICogQHBhcmFtIHthcnJheX0gLSBBcnJheSBidWZmZXIgb2YgTUlESSBmaWxlIChvcHRpb25hbCkuXG4gKi9cbmNsYXNzIFBsYXllciB7XG5cdGNvbnN0cnVjdG9yKGV2ZW50SGFuZGxlciwgYnVmZmVyKSB7XG5cdFx0dGhpcy5zYW1wbGVSYXRlID0gNTsgLy8gbWlsbGlzZWNvbmRzXG5cdFx0dGhpcy5zdGFydFRpbWUgPSAwO1xuXHRcdHRoaXMuYnVmZmVyID0gYnVmZmVyIHx8IG51bGw7XG5cdFx0dGhpcy5kaXZpc2lvbjtcblx0XHR0aGlzLmZvcm1hdDtcblx0XHR0aGlzLnNldEludGVydmFsSWQgPSBmYWxzZTtcblx0XHR0aGlzLnRyYWNrcyA9IFtdO1xuXHRcdHRoaXMudGVtcG8gPSAxMjA7XG5cdFx0dGhpcy5zdGFydFRpY2sgPSAwO1xuXHRcdHRoaXMudGljayA9IDA7XG5cdFx0dGhpcy5sYXN0VGljayA9IG51bGw7XG5cdFx0dGhpcy5pbkxvb3AgPSBmYWxzZTtcblx0XHR0aGlzLnRvdGFsVGlja3MgPSAwO1xuXHRcdHRoaXMuZXZlbnRzID0gW107XG5cdFx0dGhpcy50b3RhbEV2ZW50cyA9IDA7XG5cdFx0dGhpcy5ldmVudExpc3RlbmVycyA9IHt9O1xuXG5cdFx0aWYgKHR5cGVvZihldmVudEhhbmRsZXIpID09PSAnZnVuY3Rpb24nKSB0aGlzLm9uKCdtaWRpRXZlbnQnLCBldmVudEhhbmRsZXIpO1xuXHR9XG5cblx0LyoqXG5cdCAqIExvYWQgYSBmaWxlIGludG8gdGhlIHBsYXllciAoTm9kZS5qcyBvbmx5KS5cblx0ICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBQYXRoIG9mIGZpbGUuXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdGxvYWRGaWxlKHBhdGgpIHtcblx0XHR2YXIgZnMgPSByZXF1aXJlKCdmcycpO1xuXHRcdHRoaXMuYnVmZmVyID0gZnMucmVhZEZpbGVTeW5jKHBhdGgpO1xuXHRcdHJldHVybiB0aGlzLmZpbGVMb2FkZWQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBMb2FkIGFuIGFycmF5IGJ1ZmZlciBpbnRvIHRoZSBwbGF5ZXIuXG5cdCAqIEBwYXJhbSB7YXJyYXl9IGFycmF5QnVmZmVyIC0gQXJyYXkgYnVmZmVyIG9mIGZpbGUgdG8gYmUgbG9hZGVkLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRsb2FkQXJyYXlCdWZmZXIoYXJyYXlCdWZmZXIpIHtcblx0XHR0aGlzLmJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KGFycmF5QnVmZmVyKTtcblx0XHRyZXR1cm4gdGhpcy5maWxlTG9hZGVkKCk7XG5cdH1cblxuXHQvKipcblx0ICogTG9hZCBhIGRhdGEgVVJJIGludG8gdGhlIHBsYXllci5cblx0ICogQHBhcmFtIHtzdHJpbmd9IGRhdGFVcmkgLSBEYXRhIFVSSSB0byBiZSBsb2FkZWQuXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdGxvYWREYXRhVXJpKGRhdGFVcmkpIHtcblx0XHQvLyBjb252ZXJ0IGJhc2U2NCB0byByYXcgYmluYXJ5IGRhdGEgaGVsZCBpbiBhIHN0cmluZy5cblx0XHQvLyBkb2Vzbid0IGhhbmRsZSBVUkxFbmNvZGVkIERhdGFVUklzIC0gc2VlIFNPIGFuc3dlciAjNjg1MDI3NiBmb3IgY29kZSB0aGF0IGRvZXMgdGhpc1xuXHRcdHZhciBieXRlU3RyaW5nID0gVXRpbHMuYXRvYihkYXRhVXJpLnNwbGl0KCcsJylbMV0pO1xuXG5cdFx0Ly8gd3JpdGUgdGhlIGJ5dGVzIG9mIHRoZSBzdHJpbmcgdG8gYW4gQXJyYXlCdWZmZXJcblx0XHR2YXIgaWEgPSBuZXcgVWludDhBcnJheShieXRlU3RyaW5nLmxlbmd0aCk7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBieXRlU3RyaW5nLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRpYVtpXSA9IGJ5dGVTdHJpbmcuY2hhckNvZGVBdChpKTtcblx0XHR9XG5cblx0XHR0aGlzLmJ1ZmZlciA9IGlhO1xuXHRcdHJldHVybiB0aGlzLmZpbGVMb2FkZWQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXQgZmlsZXNpemUgb2YgbG9hZGVkIGZpbGUgaW4gbnVtYmVyIG9mIGJ5dGVzLlxuXHQgKiBAcmV0dXJuIHtudW1iZXJ9IC0gVGhlIGZpbGVzaXplLlxuXHQgKi9cblx0Z2V0RmlsZXNpemUoKSB7XG5cdFx0cmV0dXJuIHRoaXMuYnVmZmVyID8gdGhpcy5idWZmZXIubGVuZ3RoIDogMDtcblx0fVxuXG5cdC8qKlxuXHQgKiBQYXJzZXMgZmlsZSBmb3IgbmVjZXNzYXJ5IGluZm9ybWF0aW9uIGFuZCBkb2VzIGEgZHJ5IHJ1biB0byBjYWxjdWxhdGUgdG90YWwgbGVuZ3RoLlxuXHQgKiBQb3B1bGF0ZXMgdGhpcy5ldmVudHMgJiB0aGlzLnRvdGFsVGlja3MuXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdGZpbGVMb2FkZWQoKSB7XG5cdFx0aWYgKCF0aGlzLnZhbGlkYXRlKCkpIHRocm93ICdJbnZhbGlkIE1JREkgZmlsZTsgc2hvdWxkIHN0YXJ0IHdpdGggTVRoZCc7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0RGl2aXNpb24oKS5nZXRGb3JtYXQoKS5nZXRUcmFja3MoKS5kcnlSdW4oKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBWYWxpZGF0ZXMgZmlsZSB1c2luZyBzaW1wbGUgbWVhbnMgLSBmaXJzdCBmb3VyIGJ5dGVzIHNob3VsZCA9PSBNVGhkLlxuXHQgKiBAcmV0dXJuIHtib29sZWFufVxuXHQgKi9cblx0dmFsaWRhdGUoKSB7XG5cdFx0cmV0dXJuIFV0aWxzLmJ5dGVzVG9MZXR0ZXJzKHRoaXMuYnVmZmVyLnNsaWNlKDAsIDQpKSA9PT0gJ01UaGQnO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldHMgTUlESSBmaWxlIGZvcm1hdCBmb3IgbG9hZGVkIGZpbGUuXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdGdldEZvcm1hdCgpIHtcblx0XHQvKlxuXHRcdE1JREkgZmlsZXMgY29tZSBpbiAzIHZhcmlhdGlvbnM6XG5cdFx0Rm9ybWF0IDAgd2hpY2ggY29udGFpbiBhIHNpbmdsZSB0cmFja1xuXHRcdEZvcm1hdCAxIHdoaWNoIGNvbnRhaW4gb25lIG9yIG1vcmUgc2ltdWx0YW5lb3VzIHRyYWNrc1xuXHRcdChpZSBhbGwgdHJhY2tzIGFyZSB0byBiZSBwbGF5ZWQgc2ltdWx0YW5lb3VzbHkpLlxuXHRcdEZvcm1hdCAyIHdoaWNoIGNvbnRhaW4gb25lIG9yIG1vcmUgaW5kZXBlbmRhbnQgdHJhY2tzXG5cdFx0KGllIGVhY2ggdHJhY2sgaXMgdG8gYmUgcGxheWVkIGluZGVwZW5kYW50bHkgb2YgdGhlIG90aGVycykuXG5cdFx0cmV0dXJuIFV0aWxzLmJ5dGVzVG9OdW1iZXIodGhpcy5idWZmZXIuc2xpY2UoOCwgMTApKTtcblx0XHQqL1xuXG5cdFx0dGhpcy5mb3JtYXQgPSBVdGlscy5ieXRlc1RvTnVtYmVyKHRoaXMuYnVmZmVyLnNsaWNlKDgsIDEwKSk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUGFyc2VzIG91dCB0cmFja3MsIHBsYWNlcyB0aGVtIGluIHRoaXMudHJhY2tzIGFuZCBpbml0aWFsaXplcyB0aGlzLnBvaW50ZXJzXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdGdldFRyYWNrcygpIHtcblx0XHR0aGlzLnRyYWNrcyA9IFtdO1xuXHRcdHRoaXMuYnVmZmVyLmZvckVhY2goZnVuY3Rpb24oYnl0ZSwgaW5kZXgpIHtcblx0XHRcdGlmIChVdGlscy5ieXRlc1RvTGV0dGVycyh0aGlzLmJ1ZmZlci5zbGljZShpbmRleCwgaW5kZXggKyA0KSkgPT0gJ01UcmsnKSB7XG5cdFx0XHRcdGxldCB0cmFja0xlbmd0aCA9IFV0aWxzLmJ5dGVzVG9OdW1iZXIodGhpcy5idWZmZXIuc2xpY2UoaW5kZXggKyA0LCBpbmRleCArIDgpKTtcblx0XHRcdFx0dGhpcy50cmFja3MucHVzaChuZXcgVHJhY2sodGhpcy50cmFja3MubGVuZ3RoLCB0aGlzLmJ1ZmZlci5zbGljZShpbmRleCArIDgsIGluZGV4ICsgOCArIHRyYWNrTGVuZ3RoKSkpO1xuXHRcdFx0fVxuXHRcdH0sIHRoaXMpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogRW5hYmxlcyBhIHRyYWNrIGZvciBwbGF5aW5nLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gdHJhY2tOdW1iZXIgLSBUcmFjayBudW1iZXJcblx0ICogQHJldHVybiB7UGxheWVyfVxuXHQgKi9cblx0ZW5hYmxlVHJhY2sodHJhY2tOdW1iZXIpIHtcblx0XHR0aGlzLnRyYWNrc1t0cmFja051bWJlciAtIDFdLmVuYWJsZSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIERpc2FibGVzIGEgdHJhY2sgZm9yIHBsYXlpbmcuXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSAtIFRyYWNrIG51bWJlclxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRkaXNhYmxlVHJhY2sodHJhY2tOdW1iZXIpIHtcblx0XHR0aGlzLnRyYWNrc1t0cmFja051bWJlciAtIDFdLmRpc2FibGUoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXRzIHF1YXJ0ZXIgbm90ZSBkaXZpc2lvbiBvZiBsb2FkZWQgTUlESSBmaWxlLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRnZXREaXZpc2lvbigpIHtcblx0XHR0aGlzLmRpdmlzaW9uID0gVXRpbHMuYnl0ZXNUb051bWJlcih0aGlzLmJ1ZmZlci5zbGljZSgxMiwgMTQpKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBUaGUgbWFpbiBwbGF5IGxvb3AuXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gLSBJbmRpY2F0ZXMgd2hldGhlciBvciBub3QgdGhpcyBpcyBiZWluZyBjYWxsZWQgc2ltcGx5IGZvciBwYXJzaW5nIHB1cnBvc2VzLiAgRGlzcmVnYXJkcyB0aW1pbmcgaWYgc28uXG5cdCAqIEByZXR1cm4ge3VuZGVmaW5lZH1cblx0ICovXG5cdHBsYXlMb29wKGRyeVJ1bikge1xuXHRcdGlmICghdGhpcy5pbkxvb3ApIHtcblx0XHRcdHRoaXMuaW5Mb29wID0gdHJ1ZTtcblx0XHRcdHRoaXMudGljayA9IHRoaXMuZ2V0Q3VycmVudFRpY2soKTtcblxuXHRcdFx0dGhpcy50cmFja3MuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuXHRcdFx0XHQvLyBIYW5kbGUgbmV4dCBldmVudFxuXHRcdFx0XHRpZiAoIWRyeVJ1biAmJiB0aGlzLmVuZE9mRmlsZSgpKSB7XG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnZW5kIG9mIGZpbGUnKVxuXHRcdFx0XHRcdHRoaXMudHJpZ2dlclBsYXllckV2ZW50KCdlbmRPZkZpbGUnKTtcblx0XHRcdFx0XHR0aGlzLnN0b3AoKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGxldCBldmVudCA9IHRyYWNrLmhhbmRsZUV2ZW50KHRoaXMudGljaywgZHJ5UnVuKTtcblxuXHRcdFx0XHRcdGlmIChkcnlSdW4gJiYgZXZlbnQgJiYgZXZlbnQuaGFzT3duUHJvcGVydHkoJ25hbWUnKSAmJiBldmVudC5uYW1lID09PSAnU2V0IFRlbXBvJykge1xuXHRcdFx0XHRcdFx0Ly8gR3JhYiB0ZW1wbyBpZiBhdmFpbGFibGUuXG5cdFx0XHRcdFx0XHR0aGlzLnRlbXBvID0gZXZlbnQuZGF0YTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoZXZlbnQgJiYgIWRyeVJ1bikgdGhpcy5lbWl0RXZlbnQoZXZlbnQpO1xuXHRcdFx0XHR9XG5cblx0XHRcdH0sIHRoaXMpO1xuXG5cdFx0XHRpZiAoIWRyeVJ1bikgdGhpcy50cmlnZ2VyUGxheWVyRXZlbnQoJ3BsYXlpbmcnLCB7dGljazogdGhpcy50aWNrfSk7XG5cdFx0XHR0aGlzLmluTG9vcCA9IGZhbHNlO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBTZXR0ZXIgZm9yIHN0YXJ0VGltZS5cblx0ICogQHBhcmFtIHtudW1iZXJ9IC0gVVRDIHRpbWVzdGFtcFxuXHQgKi9cblx0c2V0U3RhcnRUaW1lKHN0YXJ0VGltZSkge1xuXHRcdHRoaXMuc3RhcnRUaW1lID0gc3RhcnRUaW1lO1xuXHR9XG5cblx0LyoqXG5cdCAqIFN0YXJ0IHBsYXlpbmcgbG9hZGVkIE1JREkgZmlsZSBpZiBub3QgYWxyZWFkeSBwbGF5aW5nLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRwbGF5KCkge1xuXHRcdGlmICh0aGlzLmlzUGxheWluZygpKSB0aHJvdyAnQWxyZWFkeSBwbGF5aW5nLi4uJztcblxuXHRcdC8vIEluaXRpYWxpemVcblx0XHRpZiAoIXRoaXMuc3RhcnRUaW1lKSB0aGlzLnN0YXJ0VGltZSA9IChuZXcgRGF0ZSgpKS5nZXRUaW1lKCk7XG5cblx0XHQvLyBTdGFydCBwbGF5IGxvb3Bcblx0XHQvL3dpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUodGhpcy5wbGF5TG9vcC5iaW5kKHRoaXMpKTtcblx0XHR0aGlzLnNldEludGVydmFsSWQgPSBzZXRJbnRlcnZhbCh0aGlzLnBsYXlMb29wLmJpbmQodGhpcyksIHRoaXMuc2FtcGxlUmF0ZSk7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBQYXVzZXMgcGxheWJhY2sgaWYgcGxheWluZy5cblx0ICogQHJldHVybiB7UGxheWVyfVxuXHQgKi9cblx0cGF1c2UoKSB7XG5cdFx0Y2xlYXJJbnRlcnZhbCh0aGlzLnNldEludGVydmFsSWQpO1xuXHRcdHRoaXMuc2V0SW50ZXJ2YWxJZCA9IGZhbHNlO1xuXHRcdHRoaXMuc3RhcnRUaWNrID0gdGhpcy50aWNrO1xuXHRcdHRoaXMuc3RhcnRUaW1lID0gMDtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBTdG9wcyBwbGF5YmFjayBpZiBwbGF5aW5nLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRzdG9wKCkge1xuXHRcdGNsZWFySW50ZXJ2YWwodGhpcy5zZXRJbnRlcnZhbElkKTtcblx0XHR0aGlzLnNldEludGVydmFsSWQgPSBmYWxzZTtcblx0XHR0aGlzLnN0YXJ0VGljayA9IDA7XG5cdFx0dGhpcy5zdGFydFRpbWUgPSAwO1xuXHRcdHRoaXMucmVzZXRUcmFja3MoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBTa2lwcyBwbGF5ZXIgcG9pbnRlciB0byBzcGVjaWZpZWQgdGljay5cblx0ICogQHBhcmFtIHtudW1iZXJ9IC0gVGljayB0byBza2lwIHRvLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRza2lwVG9UaWNrKHRpY2spIHtcblx0XHR0aGlzLnN0b3AoKTtcblx0XHR0aGlzLnN0YXJ0VGljayA9IHRpY2s7XG5cblx0XHQvLyBOZWVkIHRvIHNldCB0cmFjayBldmVudCBpbmRleGVzIHRvIHRoZSBuZWFyZXN0IHBvc3NpYmxlIGV2ZW50IHRvIHRoZSBzcGVjaWZpZWQgdGljay5cblx0XHR0aGlzLnRyYWNrcy5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG5cdFx0XHR0cmFjay5zZXRFdmVudEluZGV4QnlUaWNrKHRpY2spO1xuXHRcdH0pO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNraXBzIHBsYXllciBwb2ludGVyIHRvIHNwZWNpZmllZCBwZXJjZW50YWdlLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gLSBQZXJjZW50IHZhbHVlIGluIGludGVnZXIgZm9ybWF0LlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRza2lwVG9QZXJjZW50KHBlcmNlbnQpIHtcblx0XHRpZiAocGVyY2VudCA8IDAgfHwgcGVyY2VudCA+IDEwMCkgdGhyb3cgXCJQZXJjZW50IG11c3QgYmUgbnVtYmVyIGJldHdlZW4gMSBhbmQgMTAwLlwiO1xuXHRcdHRoaXMuc2tpcFRvVGljayhNYXRoLnJvdW5kKHBlcmNlbnQgLyAxMDAgKiB0aGlzLnRvdGFsVGlja3MpKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBTa2lwcyBwbGF5ZXIgcG9pbnRlciB0byBzcGVjaWZpZWQgc2Vjb25kcy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IC0gU2Vjb25kcyB0byBza2lwIHRvLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRza2lwVG9TZWNvbmRzKHNlY29uZHMpIHtcblx0XHR2YXIgc29uZ1RpbWUgPSB0aGlzLmdldFNvbmdUaW1lKCk7XG5cdFx0aWYgKHNlY29uZHMgPCAwIHx8IHNlY29uZHMgPiBzb25nVGltZSkgdGhyb3cgc2Vjb25kcyArIFwiIHNlY29uZHMgbm90IHdpdGhpbiBzb25nIHRpbWUgb2YgXCIgKyBzb25nVGltZTtcblx0XHR0aGlzLnNraXBUb1BlcmNlbnQoc2Vjb25kcyAvIHNvbmdUaW1lICogMTAwKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBDaGVja3MgaWYgcGxheWVyIGlzIHBsYXlpbmdcblx0ICogQHJldHVybiB7Ym9vbGVhbn1cblx0ICovXG5cdGlzUGxheWluZygpIHtcblx0XHRyZXR1cm4gdGhpcy5zZXRJbnRlcnZhbElkID4gMCB8fCB0eXBlb2YgdGhpcy5zZXRJbnRlcnZhbElkID09PSAnb2JqZWN0Jztcblx0fVxuXG5cdC8qKlxuXHQgKiBQbGF5cyB0aGUgbG9hZGVkIE1JREkgZmlsZSB3aXRob3V0IHJlZ2FyZCBmb3IgdGltaW5nIGFuZCBzYXZlcyBldmVudHMgaW4gdGhpcy5ldmVudHMuICBFc3NlbnRpYWxseSB1c2VkIGFzIGEgcGFyc2VyLlxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRkcnlSdW4oKSB7XG5cdFx0Ly8gUmVzZXQgdHJhY2tzIGZpcnN0XG5cdFx0dGhpcy5yZXNldFRyYWNrcygpO1xuXHRcdHdoaWxlICghdGhpcy5lbmRPZkZpbGUoKSkgdGhpcy5wbGF5TG9vcCh0cnVlKTtcblx0XHR0aGlzLmV2ZW50cyA9IHRoaXMuZ2V0RXZlbnRzKCk7XG5cdFx0dGhpcy50b3RhbEV2ZW50cyA9IHRoaXMuZ2V0VG90YWxFdmVudHMoKTtcblx0XHR0aGlzLnRvdGFsVGlja3MgPSB0aGlzLmdldFRvdGFsVGlja3MoKTtcblx0XHR0aGlzLnN0YXJ0VGljayA9IDA7XG5cdFx0dGhpcy5zdGFydFRpbWUgPSAwO1xuXG5cdFx0Ly8gTGVhdmUgdHJhY2tzIGluIHByaXN0aW5lIGNvbmRpc2hcblx0XHR0aGlzLnJlc2V0VHJhY2tzKCk7XG5cblx0XHQvL2NvbnNvbGUubG9nKCdTb25nIHRpbWU6ICcgKyB0aGlzLmdldFNvbmdUaW1lKCkgKyAnIHNlY29uZHMgLyAnICsgdGhpcy50b3RhbFRpY2tzICsgJyB0aWNrcy4nKTtcblxuXHRcdHRoaXMudHJpZ2dlclBsYXllckV2ZW50KCdmaWxlTG9hZGVkJywgdGhpcyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUmVzZXRzIHBsYXkgcG9pbnRlcnMgZm9yIGFsbCB0cmFja3MuXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdHJlc2V0VHJhY2tzKCkge1xuXHRcdHRoaXMudHJhY2tzLmZvckVhY2godHJhY2sgPT4gdHJhY2sucmVzZXQoKSk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogR2V0cyBhbiBhcnJheSBvZiBldmVudHMgZ3JvdXBlZCBieSB0cmFjay5cblx0ICogQHJldHVybiB7YXJyYXl9XG5cdCAqL1xuXHRnZXRFdmVudHMoKSB7XG5cdFx0cmV0dXJuIHRoaXMudHJhY2tzLm1hcCh0cmFjayA9PiB0cmFjay5ldmVudHMpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldHMgdG90YWwgbnVtYmVyIG9mIHRpY2tzIGluIHRoZSBsb2FkZWQgTUlESSBmaWxlLlxuXHQgKiBAcmV0dXJuIHtudW1iZXJ9XG5cdCAqL1xuXHRnZXRUb3RhbFRpY2tzKCkge1xuXHRcdHJldHVybiBNYXRoLm1heC5hcHBseShudWxsLCB0aGlzLnRyYWNrcy5tYXAodHJhY2sgPT4gdHJhY2suZGVsdGEpKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXRzIHRvdGFsIG51bWJlciBvZiBldmVudHMgaW4gdGhlIGxvYWRlZCBNSURJIGZpbGUuXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldFRvdGFsRXZlbnRzKCkge1xuXHRcdHJldHVybiB0aGlzLnRyYWNrcy5yZWR1Y2UoKGEsIGIpID0+IHtyZXR1cm4ge2V2ZW50czoge2xlbmd0aDogYS5ldmVudHMubGVuZ3RoICsgYi5ldmVudHMubGVuZ3RofX19LCB7ZXZlbnRzOiB7bGVuZ3RoOiAwfX0pLmV2ZW50cy5sZW5ndGg7XG5cdH1cblxuXHQvKipcblx0ICogR2V0cyBzb25nIGR1cmF0aW9uIGluIHNlY29uZHMuXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldFNvbmdUaW1lKCkge1xuXHRcdHJldHVybiB0aGlzLnRvdGFsVGlja3MgLyB0aGlzLmRpdmlzaW9uIC8gdGhpcy50ZW1wbyAqIDYwO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldHMgcmVtYWluaW5nIG51bWJlciBvZiBzZWNvbmRzIGluIHBsYXliYWNrLlxuXHQgKiBAcmV0dXJuIHtudW1iZXJ9XG5cdCAqL1xuXHRnZXRTb25nVGltZVJlbWFpbmluZygpIHtcblx0XHRyZXR1cm4gTWF0aC5yb3VuZCgodGhpcy50b3RhbFRpY2tzIC0gdGhpcy50aWNrKSAvIHRoaXMuZGl2aXNpb24gLyB0aGlzLnRlbXBvICogNjApO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldHMgcmVtYWluaW5nIHBlcmNlbnQgb2YgcGxheWJhY2suXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldFNvbmdQZXJjZW50UmVtYWluaW5nKCkge1xuXHRcdHJldHVybiBNYXRoLnJvdW5kKHRoaXMuZ2V0U29uZ1RpbWVSZW1haW5pbmcoKSAvIHRoaXMuZ2V0U29uZ1RpbWUoKSAqIDEwMCk7XG5cdH1cblxuXHQvKipcblx0ICogTnVtYmVyIG9mIGJ5dGVzIHByb2Nlc3NlZCBpbiB0aGUgbG9hZGVkIE1JREkgZmlsZS5cblx0ICogQHJldHVybiB7bnVtYmVyfVxuXHQgKi9cblx0Ynl0ZXNQcm9jZXNzZWQoKSB7XG5cdFx0Ly8gQ3VycmVudGx5IGFzc3VtZSBoZWFkZXIgY2h1bmsgaXMgc3RyaWN0bHkgMTQgYnl0ZXNcblx0XHRyZXR1cm4gMTQgKyB0aGlzLnRyYWNrcy5sZW5ndGggKiA4ICsgdGhpcy50cmFja3MucmVkdWNlKChhLCBiKSA9PiB7cmV0dXJuIHtwb2ludGVyOiBhLnBvaW50ZXIgKyBiLnBvaW50ZXJ9fSwge3BvaW50ZXI6IDB9KS5wb2ludGVyO1xuXHR9XG5cblx0LyoqXG5cdCAqIE51bWJlciBvZiBldmVudHMgcGxheWVkIHVwIHRvIHRoaXMgcG9pbnQuXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGV2ZW50c1BsYXllZCgpIHtcblx0XHRyZXR1cm4gdGhpcy50cmFja3MucmVkdWNlKChhLCBiKSA9PiB7cmV0dXJuIHtldmVudEluZGV4OiBhLmV2ZW50SW5kZXggKyBiLmV2ZW50SW5kZXh9fSwge2V2ZW50SW5kZXg6IDB9KS5ldmVudEluZGV4O1xuXHR9XG5cblx0LyoqXG5cdCAqIERldGVybWluZXMgaWYgdGhlIHBsYXllciBwb2ludGVyIGhhcyByZWFjaGVkIHRoZSBlbmQgb2YgdGhlIGxvYWRlZCBNSURJIGZpbGUuXG5cdCAqIFVzZWQgaW4gdHdvIHdheXM6XG5cdCAqIDEuIElmIHBsYXlpbmcgcmVzdWx0IGlzIGJhc2VkIG9uIGxvYWRlZCBKU09OIGV2ZW50cy5cblx0ICogMi4gSWYgcGFyc2luZyAoZHJ5UnVuKSBpdCdzIGJhc2VkIG9uIHRoZSBhY3R1YWwgYnVmZmVyIGxlbmd0aCB2cyBieXRlcyBwcm9jZXNzZWQuXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59XG5cdCAqL1xuXHRlbmRPZkZpbGUoKSB7XG5cdFx0aWYgKHRoaXMuaXNQbGF5aW5nKCkpIHtcblx0XHRcdHJldHVybiB0aGlzLmV2ZW50c1BsYXllZCgpID09IHRoaXMudG90YWxFdmVudHM7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuYnl0ZXNQcm9jZXNzZWQoKSA9PSB0aGlzLmJ1ZmZlci5sZW5ndGg7XG5cdH1cblxuXHQvKipcblx0ICogR2V0cyB0aGUgY3VycmVudCB0aWNrIG51bWJlciBpbiBwbGF5YmFjay5cblx0ICogQHJldHVybiB7bnVtYmVyfVxuXHQgKi9cblx0Z2V0Q3VycmVudFRpY2soKSB7XG5cdFx0cmV0dXJuIE1hdGgucm91bmQoKChuZXcgRGF0ZSgpKS5nZXRUaW1lKCkgLSB0aGlzLnN0YXJ0VGltZSkgLyAxMDAwICogKHRoaXMuZGl2aXNpb24gKiAodGhpcy50ZW1wbyAvIDYwKSkpICsgdGhpcy5zdGFydFRpY2s7XG5cdH1cblxuXHQvKipcblx0ICogU2VuZHMgTUlESSBldmVudCBvdXQgdG8gbGlzdGVuZXIuXG5cdCAqIEBwYXJhbSB7b2JqZWN0fVxuXHQgKiBAcmV0dXJuIHtQbGF5ZXJ9XG5cdCAqL1xuXHRlbWl0RXZlbnQoZXZlbnQpIHtcblx0XHR0aGlzLnRyaWdnZXJQbGF5ZXJFdmVudCgnbWlkaUV2ZW50JywgZXZlbnQpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFN1YnNjcmliZXMgZXZlbnRzIHRvIGxpc3RlbmVycyBcblx0ICogQHBhcmFtIHtzdHJpbmd9IC0gTmFtZSBvZiBldmVudCB0byBzdWJzY3JpYmUgdG8uXG5cdCAqIEBwYXJhbSB7ZnVuY3Rpb259IC0gQ2FsbGJhY2sgdG8gZmlyZSB3aGVuIGV2ZW50IGlzIGJyb2FkY2FzdC5cblx0ICogQHJldHVybiB7UGxheWVyfVxuXHQgKi9cblx0b24ocGxheWVyRXZlbnQsIGZuKSB7XG5cdFx0aWYgKCF0aGlzLmV2ZW50TGlzdGVuZXJzLmhhc093blByb3BlcnR5KHBsYXllckV2ZW50KSkgdGhpcy5ldmVudExpc3RlbmVyc1twbGF5ZXJFdmVudF0gPSBbXTtcblx0XHR0aGlzLmV2ZW50TGlzdGVuZXJzW3BsYXllckV2ZW50XS5wdXNoKGZuKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBCcm9hZGNhc3RzIGV2ZW50IHRvIHRyaWdnZXIgc3Vic2NyaWJlZCBjYWxsYmFja3MuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSAtIE5hbWUgb2YgZXZlbnQuXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSAtIERhdGEgdG8gYmUgcGFzc2VkIHRvIHN1YnNjcmliZXIgY2FsbGJhY2suXG5cdCAqIEByZXR1cm4ge1BsYXllcn1cblx0ICovXG5cdHRyaWdnZXJQbGF5ZXJFdmVudChwbGF5ZXJFdmVudCwgZGF0YSkge1xuXHRcdGlmICh0aGlzLmV2ZW50TGlzdGVuZXJzLmhhc093blByb3BlcnR5KHBsYXllckV2ZW50KSkgdGhpcy5ldmVudExpc3RlbmVyc1twbGF5ZXJFdmVudF0uZm9yRWFjaChmbiA9PiBmbihkYXRhIHx8IHt9KSk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5leHBvcnRzLlBsYXllciA9IFBsYXllcjtcbi8qKlxuICogQ2xhc3MgcmVwcmVzZW50aW5nIGEgdHJhY2suICBDb250YWlucyBtZXRob2RzIGZvciBwYXJzaW5nIGV2ZW50cyBhbmQga2VlcGluZyB0cmFjayBvZiBwb2ludGVyLlxuICovXG5jbGFzcyBUcmFja1x0e1xuXHRjb25zdHJ1Y3RvcihpbmRleCwgZGF0YSkge1xuXHRcdHRoaXMuZW5hYmxlZCA9IHRydWU7XG5cdFx0dGhpcy5ldmVudEluZGV4ID0gMDtcblx0XHR0aGlzLnBvaW50ZXIgPSAwO1xuXHRcdHRoaXMubGFzdFRpY2sgPSAwO1xuXHRcdHRoaXMubGFzdFN0YXR1cyA9IG51bGw7XG5cdFx0dGhpcy5pbmRleCA9IGluZGV4O1xuXHRcdHRoaXMuZGF0YSA9IGRhdGE7XG5cdFx0dGhpcy5kZWx0YSA9IDA7XG5cdFx0dGhpcy5ydW5uaW5nRGVsdGEgPSAwO1xuXHRcdHRoaXMuZXZlbnRzID0gW107XG5cdH1cblxuXHQvKipcblx0ICogUmVzZXRzIGFsbCBzdGF0ZWZ1bCB0cmFjayBpbmZvcm1haW9uIHVzZWQgZHVyaW5nIHBsYXliYWNrLlxuXHQgKiBAcmV0dXJuIHtUcmFja31cblx0ICovXG5cdHJlc2V0KCkge1xuXHRcdHRoaXMuZW5hYmxlZCA9IHRydWU7XG5cdFx0dGhpcy5ldmVudEluZGV4ID0gMDtcblx0XHR0aGlzLnBvaW50ZXIgPSAwO1xuXHRcdHRoaXMubGFzdFRpY2sgPSAwO1xuXHRcdHRoaXMubGFzdFN0YXR1cyA9IG51bGw7XG5cdFx0dGhpcy5kZWx0YSA9IDA7XG5cdFx0dGhpcy5ydW5uaW5nRGVsdGEgPSAwO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhpcyB0cmFjayB0byBiZSBlbmFibGVkIGR1cmluZyBwbGF5YmFjay5cblx0ICogQHJldHVybiB7VHJhY2t9XG5cdCAqL1xuXHRlbmFibGUoKSB7XG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIHRoaXMgdHJhY2sgdG8gYmUgZGlzYWJsZWQgZHVyaW5nIHBsYXliYWNrLlxuXHQgKiBAcmV0dXJuIHtUcmFja31cblx0ICovXG5cdGRpc2FibGUoKSB7XG5cdFx0dGhpcy5lbmFibGVkID0gZmFsc2U7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgdHJhY2sgZXZlbnQgaW5kZXggdG8gdGhlIG5lYXJlc3QgZXZlbnQgdG8gdGhlIGdpdmVuIHRpY2suXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSB0aWNrXG5cdCAqIEByZXR1cm4ge1RyYWNrfVxuXHQgKi9cblx0c2V0RXZlbnRJbmRleEJ5VGljayh0aWNrKSB7XG5cdFx0dGljayA9IHRpY2sgfHwgMDtcblxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5ldmVudHMpIHtcblx0XHRcdGlmICh0aGlzLmV2ZW50c1tpXS50aWNrID49IHRpY2spIHtcblx0XHRcdFx0dGhpcy5ldmVudEluZGV4ID0gaTtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEdldHMgYnl0ZSBsb2NhdGVkIGF0IHBvaW50ZXIgcG9zaXRpb24uXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldEN1cnJlbnRCeXRlKCkge1xuXHRcdHJldHVybiB0aGlzLmRhdGFbdGhpcy5wb2ludGVyXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXRzIGNvdW50IG9mIGRlbHRhIGJ5dGVzIGFuZCBjdXJyZW50IHBvaW50ZXIgcG9zaXRpb24uXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldERlbHRhQnl0ZUNvdW50KCkge1xuXHRcdC8vIEdldCBieXRlIGNvdW50IG9mIGRlbHRhIFZMVlxuXHRcdC8vIGh0dHA6Ly93d3cuY2Nhcmgub3JnL2NvdXJzZXMvMjUzL2hhbmRvdXQvdmx2L1xuXHRcdC8vIElmIGJ5dGUgaXMgZ3JlYXRlciBvciBlcXVhbCB0byA4MGggKDEyOCBkZWNpbWFsKSB0aGVuIHRoZSBuZXh0IGJ5dGVcblx0ICAgIC8vIGlzIGFsc28gcGFydCBvZiB0aGUgVkxWLFxuXHQgICBcdC8vIGVsc2UgYnl0ZSBpcyB0aGUgbGFzdCBieXRlIGluIGEgVkxWLlxuXHQgICBcdHZhciBjdXJyZW50Qnl0ZSA9IHRoaXMuZ2V0Q3VycmVudEJ5dGUoKTtcblx0ICAgXHR2YXIgYnl0ZUNvdW50ID0gMTtcblxuXHRcdHdoaWxlIChjdXJyZW50Qnl0ZSA+PSAxMjgpIHtcblx0XHRcdGN1cnJlbnRCeXRlID0gdGhpcy5kYXRhW3RoaXMucG9pbnRlciArIGJ5dGVDb3VudF07XG5cdFx0XHRieXRlQ291bnQrKztcblx0XHR9XG5cblx0XHRyZXR1cm4gYnl0ZUNvdW50O1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldCBkZWx0YSB2YWx1ZSBhdCBjdXJyZW50IHBvaW50ZXIgcG9zaXRpb24uXG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdGdldERlbHRhKCkge1xuXHRcdHJldHVybiBVdGlscy5yZWFkVmFySW50KHRoaXMuZGF0YS5zbGljZSh0aGlzLnBvaW50ZXIsIHRoaXMucG9pbnRlciArIHRoaXMuZ2V0RGVsdGFCeXRlQ291bnQoKSkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEhhbmRsZXMgZXZlbnQgd2l0aGluIGEgZ2l2ZW4gdHJhY2sgc3RhcnRpbmcgYXQgc3BlY2lmaWVkIGluZGV4XG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBjdXJyZW50VGlja1xuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGRyeVJ1biAtIElmIHRydWUgZXZlbnRzIHdpbGwgYmUgcGFyc2VkIGFuZCByZXR1cm5lZCByZWdhcmRsZXNzIG9mIHRpbWUuXG5cdCAqL1xuXHRoYW5kbGVFdmVudChjdXJyZW50VGljaywgZHJ5UnVuKSB7XG5cdFx0ZHJ5UnVuID0gZHJ5UnVuIHx8IGZhbHNlO1xuXG5cdFx0aWYgKGRyeVJ1bikge1xuXHRcdFx0dmFyIGVsYXBzZWRUaWNrcyA9IGN1cnJlbnRUaWNrIC0gdGhpcy5sYXN0VGljaztcblx0XHRcdHZhciBkZWx0YSA9IHRoaXMuZ2V0RGVsdGEoKTtcblx0XHRcdHZhciBldmVudFJlYWR5ID0gZWxhcHNlZFRpY2tzID49IGRlbHRhO1xuXG5cdFx0XHRpZiAodGhpcy5wb2ludGVyIDwgdGhpcy5kYXRhLmxlbmd0aCAmJiAoZHJ5UnVuIHx8IGV2ZW50UmVhZHkpKSB7XG5cdFx0XHRcdGxldCBldmVudCA9IHRoaXMucGFyc2VFdmVudCgpO1xuXHRcdFx0XHRpZiAodGhpcy5lbmFibGVkKSByZXR1cm4gZXZlbnQ7XG5cdFx0XHRcdC8vIFJlY3Vyc2l2ZWx5IGNhbGwgdGhpcyBmdW5jdGlvbiBmb3IgZWFjaCBldmVudCBhaGVhZCB0aGF0IGhhcyAwIGRlbHRhIHRpbWU/XG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gTGV0J3MgYWN0dWFsbHkgcGxheSB0aGUgTUlESSBmcm9tIHRoZSBnZW5lcmF0ZWQgSlNPTiBldmVudHMgY3JlYXRlZCBieSB0aGUgZHJ5IHJ1bi5cblx0XHRcdGlmICh0aGlzLmV2ZW50c1t0aGlzLmV2ZW50SW5kZXhdICYmIHRoaXMuZXZlbnRzW3RoaXMuZXZlbnRJbmRleF0udGljayA8PSBjdXJyZW50VGljaykge1xuXHRcdFx0XHR0aGlzLmV2ZW50SW5kZXgrKztcblx0XHRcdFx0aWYgKHRoaXMuZW5hYmxlZCkgcmV0dXJuIHRoaXMuZXZlbnRzW3RoaXMuZXZlbnRJbmRleCAtIDFdO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldCBzdHJpbmcgZGF0YSBmcm9tIGV2ZW50LlxuXHQgKiBAcGFyYW0ge251bWJlcn0gZXZlbnRTdGFydEluZGV4XG5cdCAqIEByZXR1cm4ge3N0cmluZ31cblx0ICovXG5cdGdldFN0cmluZ0RhdGEoZXZlbnRTdGFydEluZGV4KSB7XG5cdFx0dmFyIGN1cnJlbnRCeXRlID0gdGhpcy5wb2ludGVyO1xuXHRcdHZhciBieXRlQ291bnQgPSAxO1xuXHRcdHZhciBsZW5ndGggPSBVdGlscy5yZWFkVmFySW50KHRoaXMuZGF0YS5zbGljZShldmVudFN0YXJ0SW5kZXggKyAyLCBldmVudFN0YXJ0SW5kZXggKyAyICsgYnl0ZUNvdW50KSk7XG5cdFx0dmFyIHN0cmluZ0xlbmd0aCA9IGxlbmd0aDtcblxuXHRcdHJldHVybiBVdGlscy5ieXRlc1RvTGV0dGVycyh0aGlzLmRhdGEuc2xpY2UoZXZlbnRTdGFydEluZGV4ICsgYnl0ZUNvdW50ICsgMiwgZXZlbnRTdGFydEluZGV4ICsgYnl0ZUNvdW50ICsgbGVuZ3RoICsgMikpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFBhcnNlcyBldmVudCBpbnRvIEpTT04gYW5kIGFkdmFuY2VzIHBvaW50ZXIgZm9yIHRoZSB0cmFja1xuXHQgKiBAcmV0dXJuIHtvYmplY3R9XG5cdCAqL1xuXHRwYXJzZUV2ZW50KCkge1xuXHRcdHZhciBldmVudFN0YXJ0SW5kZXggPSB0aGlzLnBvaW50ZXIgKyB0aGlzLmdldERlbHRhQnl0ZUNvdW50KCk7XG5cdFx0dmFyIGV2ZW50SnNvbiA9IHt9O1xuXHRcdHZhciBkZWx0YUJ5dGVDb3VudCA9IHRoaXMuZ2V0RGVsdGFCeXRlQ291bnQoKTtcblx0XHRldmVudEpzb24udHJhY2sgPSB0aGlzLmluZGV4ICsgMTtcblx0XHRldmVudEpzb24uZGVsdGEgPSB0aGlzLmdldERlbHRhKCk7XG5cdFx0dGhpcy5sYXN0VGljayA9IHRoaXMubGFzdFRpY2sgKyBldmVudEpzb24uZGVsdGE7XG5cdFx0dGhpcy5ydW5uaW5nRGVsdGEgKz0gZXZlbnRKc29uLmRlbHRhO1xuXHRcdGV2ZW50SnNvbi50aWNrID0gdGhpcy5ydW5uaW5nRGVsdGE7XG5cdFx0ZXZlbnRKc29uLmJ5dGVJbmRleCA9IHRoaXMucG9pbnRlcjtcblxuXHRcdC8vZXZlbnRKc29uLnJhdyA9IGV2ZW50O1xuXHRcdGlmICh0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4XSA9PSAweGZmKSB7XG5cdFx0XHQvLyBNZXRhIEV2ZW50XG5cblx0XHRcdC8vIElmIHRoaXMgaXMgYSBtZXRhIGV2ZW50IHdlIHNob3VsZCBlbWl0IHRoZSBkYXRhIGFuZCBpbW1lZGlhdGVseSBtb3ZlIHRvIHRoZSBuZXh0IGV2ZW50XG5cdFx0XHQvLyBvdGhlcndpc2UgaWYgd2UgbGV0IGl0IHJ1biB0aHJvdWdoIHRoZSBuZXh0IGN5Y2xlIGEgc2xpZ2h0IGRlbGF5IHdpbGwgYWNjdW11bGF0ZSBpZiBtdWx0aXBsZSB0cmFja3Ncblx0XHRcdC8vIGFyZSBiZWluZyBwbGF5ZWQgc2ltdWx0YW5lb3VzbHlcblxuXHRcdFx0c3dpdGNoKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXSkge1xuXHRcdFx0XHRjYXNlIDB4MDA6IC8vIFNlcXVlbmNlIE51bWJlclxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1NlcXVlbmNlIE51bWJlcic7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHgwMTogLy8gVGV4dCBFdmVudFxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1RleHQgRXZlbnQnO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5zdHJpbmcgPSB0aGlzLmdldFN0cmluZ0RhdGEoZXZlbnRTdGFydEluZGV4KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDAyOiAvLyBDb3B5cmlnaHQgTm90aWNlXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnQ29weXJpZ2h0IE5vdGljZSc7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHgwMzogLy8gU2VxdWVuY2UvVHJhY2sgTmFtZVxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1NlcXVlbmNlL1RyYWNrIE5hbWUnO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5zdHJpbmcgPSB0aGlzLmdldFN0cmluZ0RhdGEoZXZlbnRTdGFydEluZGV4KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDA0OiAvLyBJbnN0cnVtZW50IE5hbWVcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdJbnN0cnVtZW50IE5hbWUnO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5zdHJpbmcgPSB0aGlzLmdldFN0cmluZ0RhdGEoZXZlbnRTdGFydEluZGV4KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDA1OiAvLyBMeXJpY1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ0x5cmljJztcblx0XHRcdFx0XHRldmVudEpzb24uc3RyaW5nID0gdGhpcy5nZXRTdHJpbmdEYXRhKGV2ZW50U3RhcnRJbmRleCk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHgwNjogLy8gTWFya2VyXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnTWFya2VyJztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDA3OiAvLyBDdWUgUG9pbnRcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdDdWUgUG9pbnQnO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5zdHJpbmcgPSB0aGlzLmdldFN0cmluZ0RhdGEoZXZlbnRTdGFydEluZGV4KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDA5OiAvLyBEZXZpY2UgTmFtZVxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ0RldmljZSBOYW1lJztcblx0XHRcdFx0XHRldmVudEpzb24uc3RyaW5nID0gdGhpcy5nZXRTdHJpbmdEYXRhKGV2ZW50U3RhcnRJbmRleCk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHgyMDogLy8gTUlESSBDaGFubmVsIFByZWZpeFxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ01JREkgQ2hhbm5lbCBQcmVmaXgnO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIDB4MjE6IC8vIE1JREkgUG9ydFxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ01JREkgUG9ydCc7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmRhdGEgPSBVdGlscy5ieXRlc1RvTnVtYmVyKFt0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4ICsgM11dKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDJGOiAvLyBFbmQgb2YgVHJhY2tcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdFbmQgb2YgVHJhY2snO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIDB4NTE6IC8vIFNldCBUZW1wb1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1NldCBUZW1wbyc7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmRhdGEgPSBNYXRoLnJvdW5kKDYwMDAwMDAwIC8gVXRpbHMuYnl0ZXNUb051bWJlcih0aGlzLmRhdGEuc2xpY2UoZXZlbnRTdGFydEluZGV4ICsgMywgZXZlbnRTdGFydEluZGV4ICsgNikpKTtcblx0XHRcdFx0XHR0aGlzLnRlbXBvID0gZXZlbnRKc29uLmRhdGE7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHg1NDogLy8gU01UUEUgT2Zmc2V0XG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnU01UUEUgT2Zmc2V0Jztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDU4OiAvLyBUaW1lIFNpZ25hdHVyZVxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1RpbWUgU2lnbmF0dXJlJztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAweDU5OiAvLyBLZXkgU2lnbmF0dXJlXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnS2V5IFNpZ25hdHVyZSc7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMHg3RjogLy8gU2VxdWVuY2VyLVNwZWNpZmljIE1ldGEtZXZlbnRcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdTZXF1ZW5jZXItU3BlY2lmaWMgTWV0YS1ldmVudCc7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnVW5rbm93bjogJyArIHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXS50b1N0cmluZygxNik7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBsZW5ndGggPSB0aGlzLmRhdGFbdGhpcy5wb2ludGVyICsgZGVsdGFCeXRlQ291bnQgKyAyXTtcblx0XHRcdC8vIFNvbWUgbWV0YSBldmVudHMgd2lsbCBoYXZlIHZsdiB0aGF0IG5lZWRzIHRvIGJlIGhhbmRsZWRcblxuXHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMyArIGxlbmd0aDtcblxuXHRcdH0gZWxzZSBpZih0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4XSA9PSAweGYwKSB7XG5cdFx0XHQvLyBTeXNleFxuXHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnU3lzZXgnO1xuXHRcdFx0dmFyIGxlbmd0aCA9IHRoaXMuZGF0YVt0aGlzLnBvaW50ZXIgKyBkZWx0YUJ5dGVDb3VudCArIDFdO1xuXHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMiArIGxlbmd0aDtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBWb2ljZSBldmVudFxuXHRcdFx0aWYgKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdIDwgMHg4MCkge1xuXHRcdFx0XHQvLyBSdW5uaW5nIHN0YXR1c1xuXHRcdFx0XHRldmVudEpzb24ucnVubmluZyA9IHRydWU7XG5cdFx0XHRcdGV2ZW50SnNvbi5ub3RlTnVtYmVyID0gdGhpcy5kYXRhW2V2ZW50U3RhcnRJbmRleF07XG5cdFx0XHRcdGV2ZW50SnNvbi5ub3RlTmFtZSA9IENvbnN0YW50cy5OT1RFU1t0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4XV07XG5cdFx0XHRcdGV2ZW50SnNvbi52ZWxvY2l0eSA9IHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXTtcblxuXHRcdFx0XHRpZiAodGhpcy5sYXN0U3RhdHVzIDw9IDB4OGYpIHtcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdOb3RlIG9mZic7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweDgwICsgMTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMubGFzdFN0YXR1cyA8PSAweDlmKSB7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnTm90ZSBvbic7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweDkwICsgMTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMucG9pbnRlciArPSBkZWx0YUJ5dGVDb3VudCArIDI7XG5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMubGFzdFN0YXR1cyA9IHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdO1xuXG5cdFx0XHRcdGlmICh0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4XSA8PSAweDhmKSB7XG5cdFx0XHRcdFx0Ly8gTm90ZSBvZmZcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdOb3RlIG9mZic7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweDgwICsgMTtcblx0XHRcdFx0XHRldmVudEpzb24ubm90ZU51bWJlciA9IHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXTtcblx0XHRcdFx0XHRldmVudEpzb24ubm90ZU5hbWUgPSBDb25zdGFudHMuTk9URVNbdGhpcy5kYXRhW2V2ZW50U3RhcnRJbmRleCArIDFdXTtcblx0XHRcdFx0XHRldmVudEpzb24udmVsb2NpdHkgPSBNYXRoLnJvdW5kKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAyXSAvIDEyNyAqIDEwMCk7XG5cdFx0XHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMztcblxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdIDw9IDB4OWYpIHtcblx0XHRcdFx0XHQvLyBOb3RlIG9uXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnTm90ZSBvbic7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweDkwICsgMTtcblx0XHRcdFx0XHRldmVudEpzb24ubm90ZU51bWJlciA9IHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXTtcblx0XHRcdFx0XHRldmVudEpzb24ubm90ZU5hbWUgPSBDb25zdGFudHMuTk9URVNbdGhpcy5kYXRhW2V2ZW50U3RhcnRJbmRleCArIDFdXTtcblx0XHRcdFx0XHRldmVudEpzb24udmVsb2NpdHkgPSBNYXRoLnJvdW5kKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAyXSAvIDEyNyAqIDEwMCk7XG5cdFx0XHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMztcblxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdIDw9IDB4YWYpIHtcblx0XHRcdFx0XHQvLyBQb2x5cGhvbmljIEtleSBQcmVzc3VyZVxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ1BvbHlwaG9uaWMgS2V5IFByZXNzdXJlJztcblx0XHRcdFx0XHRldmVudEpzb24uY2hhbm5lbCA9IHRoaXMubGFzdFN0YXR1cyAtIDB4YTAgKyAxO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5ub3RlID0gQ29uc3RhbnRzLk5PVEVTW3RoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXggKyAxXV07XG5cdFx0XHRcdFx0ZXZlbnRKc29uLnByZXNzdXJlID0gZXZlbnRbMl07XG5cdFx0XHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMztcblxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdIDw9IDB4YmYpIHtcblx0XHRcdFx0XHQvLyBDb250cm9sbGVyIENoYW5nZVxuXHRcdFx0XHRcdGV2ZW50SnNvbi5uYW1lID0gJ0NvbnRyb2xsZXIgQ2hhbmdlJztcblx0XHRcdFx0XHRldmVudEpzb24uY2hhbm5lbCA9IHRoaXMubGFzdFN0YXR1cyAtIDB4YjAgKyAxO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5udW1iZXIgPSB0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4ICsgMV07XG5cdFx0XHRcdFx0ZXZlbnRKc29uLnZhbHVlID0gdGhpcy5kYXRhW2V2ZW50U3RhcnRJbmRleCArIDJdO1xuXHRcdFx0XHRcdHRoaXMucG9pbnRlciArPSBkZWx0YUJ5dGVDb3VudCArIDM7XG5cblx0XHRcdFx0fSBlbHNlIGlmICh0aGlzLmRhdGFbZXZlbnRTdGFydEluZGV4XSA8PSAweGNmKSB7XG5cdFx0XHRcdFx0Ly8gUHJvZ3JhbSBDaGFuZ2Vcblx0XHRcdFx0XHRldmVudEpzb24ubmFtZSA9ICdQcm9ncmFtIENoYW5nZSc7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweGMwICsgMTtcblx0XHRcdFx0XHR0aGlzLnBvaW50ZXIgKz0gZGVsdGFCeXRlQ291bnQgKyAyO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGhpcy5kYXRhW2V2ZW50U3RhcnRJbmRleF0gPD0gMHhkZikge1xuXHRcdFx0XHRcdC8vIENoYW5uZWwgS2V5IFByZXNzdXJlXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnQ2hhbm5lbCBLZXkgUHJlc3N1cmUnO1xuXHRcdFx0XHRcdGV2ZW50SnNvbi5jaGFubmVsID0gdGhpcy5sYXN0U3RhdHVzIC0gMHhkMCArIDE7XG5cdFx0XHRcdFx0dGhpcy5wb2ludGVyICs9IGRlbHRhQnl0ZUNvdW50ICsgMjtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKHRoaXMuZGF0YVtldmVudFN0YXJ0SW5kZXhdIDw9IDB4ZWYpIHtcblx0XHRcdFx0XHQvLyBQaXRjaCBCZW5kXG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnUGl0Y2ggQmVuZCc7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLmNoYW5uZWwgPSB0aGlzLmxhc3RTdGF0dXMgLSAweGUwICsgMTtcblx0XHRcdFx0XHR0aGlzLnBvaW50ZXIgKz0gZGVsdGFCeXRlQ291bnQgKyAzO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZXZlbnRKc29uLm5hbWUgPSAnVW5rbm93bi4gIFBvaW50ZXI6ICcgKyB0aGlzLnBvaW50ZXIudG9TdHJpbmcoKSArICcgJyAgKyBldmVudFN0YXJ0SW5kZXgudG9TdHJpbmcoKSArICcgJyArIHRoaXMuZGF0YS5sZW5ndGg7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLmRlbHRhICs9IGV2ZW50SnNvbi5kZWx0YTtcblx0XHR0aGlzLmV2ZW50cy5wdXNoKGV2ZW50SnNvbik7XG5cblx0XHRyZXR1cm4gZXZlbnRKc29uO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgdHJ1ZSBpZiBwb2ludGVyIGhhcyByZWFjaGVkIHRoZSBlbmQgb2YgdGhlIHRyYWNrLlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59XG5cdCAqL1xuXHRlbmRPZlRyYWNrKCkge1xuXHRcdGlmICh0aGlzLmRhdGFbdGhpcy5wb2ludGVyICsgMV0gPT0gMHhmZiAmJiB0aGlzLmRhdGFbdGhpcy5wb2ludGVyICsgMl0gPT0gMHgyZiAmJiB0aGlzLmRhdGFbdGhpcy5wb2ludGVyICsgM10gPT0gMHgwMCkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59XG4vKipcbiAqIENvbnRhaW5zIG1pc2Mgc3RhdGljIHV0aWxpdHkgbWV0aG9kcy5cbiAqL1xuY2xhc3MgVXRpbHMge1xuXG5cdC8qKlxuXHQgKiBDb252ZXJ0cyBhIHNpbmdsZSBieXRlIHRvIGEgaGV4IHN0cmluZy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IGJ5dGVcblx0ICogQHJldHVybiB7c3RyaW5nfVxuXHQgKi9cblx0c3RhdGljIGJ5dGVUb0hleChieXRlKSB7XG5cdFx0Ly8gRW5zdXJlIGhleCBzdHJpbmcgYWx3YXlzIGhhcyB0d28gY2hhcnNcblx0XHRyZXR1cm4gKCcwJyArIGJ5dGUudG9TdHJpbmcoMTYpKS5zbGljZSgtMik7XG5cdH1cblxuXHQvKipcblx0ICogQ29udmVydHMgYW4gYXJyYXkgb2YgYnl0ZXMgdG8gYSBoZXggc3RyaW5nLlxuXHQgKiBAcGFyYW0ge2FycmF5fSBieXRlQXJyYXlcblx0ICogQHJldHVybiB7c3RyaW5nfVxuXHQgKi9cblx0c3RhdGljIGJ5dGVzVG9IZXgoYnl0ZUFycmF5KSB7XG5cdFx0dmFyIGhleCA9IFtdO1xuXHRcdGJ5dGVBcnJheS5mb3JFYWNoKGJ5dGUgPT4gaGV4LnB1c2goVXRpbHMuYnl0ZVRvSGV4KGJ5dGUpKSk7XG5cdFx0cmV0dXJuIGhleC5qb2luKCcnKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb252ZXJ0cyBhIGhleCBzdHJpbmcgdG8gYSBudW1iZXIuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBoZXhTdHJpbmdcblx0ICogQHJldHVybiB7bnVtYmVyfVxuXHQgKi9cblx0c3RhdGljIGhleFRvTnVtYmVyKGhleFN0cmluZykge1xuXHRcdHJldHVybiBwYXJzZUludChoZXhTdHJpbmcsIDE2KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb252ZXJ0cyBhbiBhcnJheSBvZiBieXRlcyB0byBhIG51bWJlci5cblx0ICogQHBhcmFtIHthcnJheX0gYnl0ZUFycmF5XG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdHN0YXRpYyBieXRlc1RvTnVtYmVyKGJ5dGVBcnJheSkge1xuXHRcdHJldHVybiBVdGlscy5oZXhUb051bWJlcihVdGlscy5ieXRlc1RvSGV4KGJ5dGVBcnJheSkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENvbnZlcnRzIGFuIGFycmF5IG9mIGJ5dGVzIHRvIGxldHRlcnMuXG5cdCAqIEBwYXJhbSB7YXJyYXl9IGJ5dGVBcnJheVxuXHQgKiBAcmV0dXJuIHtzdHJpbmd9XG5cdCAqL1xuXHRzdGF0aWMgYnl0ZXNUb0xldHRlcnMoYnl0ZUFycmF5KSB7XG5cdFx0dmFyIGxldHRlcnMgPSBbXTtcblx0XHRieXRlQXJyYXkuZm9yRWFjaChieXRlID0+IGxldHRlcnMucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGUpKSk7XG5cdFx0cmV0dXJuIGxldHRlcnMuam9pbignJyk7XG5cdH1cblxuXHQvKipcblx0ICogQ29udmVydHMgYSBkZWNpbWFsIHRvIGl0J3MgYmluYXJ5IHJlcHJlc2VudGF0aW9uLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gZGVjXG5cdCAqIEByZXR1cm4ge3N0cmluZ31cblx0ICovXG5cdHN0YXRpYyBkZWNUb0JpbmFyeShkZWMpIHtcbiAgICBcdHJldHVybiAoZGVjID4+PiAwKS50b1N0cmluZygyKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZWFkcyBhIHZhcmlhYmxlIGxlbmd0aCB2YWx1ZS5cblx0ICogQHBhcmFtIHthcnJheX0gYnl0ZUFycmF5XG5cdCAqIEByZXR1cm4ge251bWJlcn1cblx0ICovXG5cdHN0YXRpYyByZWFkVmFySW50KGJ5dGVBcnJheSkge1xuXHRcdHZhciByZXN1bHQgPSAwO1xuXHRcdGJ5dGVBcnJheS5mb3JFYWNoKG51bWJlciA9PiB7XG5cdFx0XHR2YXIgYiA9IG51bWJlcjtcblx0XHRcdGlmIChiICYgMHg4MCkge1xuXHRcdFx0XHRyZXN1bHQgKz0gKGIgJiAweDdmKTtcblx0XHRcdFx0cmVzdWx0IDw8PSA3O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0LyogYiBpcyB0aGUgbGFzdCBieXRlICovXG5cdFx0XHRcdHJlc3VsdCArPSBiO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fVxuXG5cdC8qKlxuXHQgKiBEZWNvZGVzIGJhc2UtNjQgZW5jb2RlZCBzdHJpbmcgXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcblx0ICogQHJldHVybiB7c3RyaW5nfVxuXHQgKi9cblx0c3RhdGljIGF0b2Ioc3RyaW5nKSB7XG5cdFx0aWYgKHR5cGVvZiBhdG9iID09PSAnZnVuY3Rpb24nKSByZXR1cm4gYXRvYihzdHJpbmcpO1xuXHRcdHJldHVybiBuZXcgQnVmZmVyKHN0cmluZywgJ2Jhc2U2NCcpLnRvU3RyaW5nKCdiaW5hcnknKTtcblx0fVxufVxuXG5leHBvcnRzLlV0aWxzID0gVXRpbHM7Il19

/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(216).Buffer))

/***/ }),
/* 216 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {/*!
 * The buffer module from node.js, for the browser.
 *
 * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
 * @license  MIT
 */
/* eslint-disable no-proto */



var base64 = __webpack_require__(217)
var ieee754 = __webpack_require__(218)
var isArray = __webpack_require__(219)

exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50

/**
 * If `Buffer.TYPED_ARRAY_SUPPORT`:
 *   === true    Use Uint8Array implementation (fastest)
 *   === false   Use Object implementation (most compatible, even IE6)
 *
 * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
 * Opera 11.6+, iOS 4.2+.
 *
 * Due to various browser bugs, sometimes the Object implementation will be used even
 * when the browser supports typed arrays.
 *
 * Note:
 *
 *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
 *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
 *
 *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
 *
 *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
 *     incorrect length in some situations.

 * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
 * get the Object implementation, which is slower but behaves correctly.
 */
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
  ? global.TYPED_ARRAY_SUPPORT
  : typedArraySupport()

/*
 * Export kMaxLength after typed array support is determined.
 */
exports.kMaxLength = kMaxLength()

function typedArraySupport () {
  try {
    var arr = new Uint8Array(1)
    arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
    return arr.foo() === 42 && // typed array instances can be augmented
        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
  } catch (e) {
    return false
  }
}

function kMaxLength () {
  return Buffer.TYPED_ARRAY_SUPPORT
    ? 0x7fffffff
    : 0x3fffffff
}

function createBuffer (that, length) {
  if (kMaxLength() < length) {
    throw new RangeError('Invalid typed array length')
  }
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    // Return an augmented `Uint8Array` instance, for best performance
    that = new Uint8Array(length)
    that.__proto__ = Buffer.prototype
  } else {
    // Fallback: Return an object instance of the Buffer class
    if (that === null) {
      that = new Buffer(length)
    }
    that.length = length
  }

  return that
}

/**
 * The Buffer constructor returns instances of `Uint8Array` that have their
 * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
 * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
 * and the `Uint8Array` methods. Square bracket notation works as expected -- it
 * returns a single octet.
 *
 * The `Uint8Array` prototype remains unmodified.
 */

function Buffer (arg, encodingOrOffset, length) {
  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
    return new Buffer(arg, encodingOrOffset, length)
  }

  // Common case.
  if (typeof arg === 'number') {
    if (typeof encodingOrOffset === 'string') {
      throw new Error(
        'If encoding is specified then the first argument must be a string'
      )
    }
    return allocUnsafe(this, arg)
  }
  return from(this, arg, encodingOrOffset, length)
}

Buffer.poolSize = 8192 // not used by this implementation

// TODO: Legacy, not needed anymore. Remove in next major version.
Buffer._augment = function (arr) {
  arr.__proto__ = Buffer.prototype
  return arr
}

function from (that, value, encodingOrOffset, length) {
  if (typeof value === 'number') {
    throw new TypeError('"value" argument must not be a number')
  }

  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
    return fromArrayBuffer(that, value, encodingOrOffset, length)
  }

  if (typeof value === 'string') {
    return fromString(that, value, encodingOrOffset)
  }

  return fromObject(that, value)
}

/**
 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
 * if value is a number.
 * Buffer.from(str[, encoding])
 * Buffer.from(array)
 * Buffer.from(buffer)
 * Buffer.from(arrayBuffer[, byteOffset[, length]])
 **/
Buffer.from = function (value, encodingOrOffset, length) {
  return from(null, value, encodingOrOffset, length)
}

if (Buffer.TYPED_ARRAY_SUPPORT) {
  Buffer.prototype.__proto__ = Uint8Array.prototype
  Buffer.__proto__ = Uint8Array
  if (typeof Symbol !== 'undefined' && Symbol.species &&
      Buffer[Symbol.species] === Buffer) {
    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
    Object.defineProperty(Buffer, Symbol.species, {
      value: null,
      configurable: true
    })
  }
}

function assertSize (size) {
  if (typeof size !== 'number') {
    throw new TypeError('"size" argument must be a number')
  } else if (size < 0) {
    throw new RangeError('"size" argument must not be negative')
  }
}

function alloc (that, size, fill, encoding) {
  assertSize(size)
  if (size <= 0) {
    return createBuffer(that, size)
  }
  if (fill !== undefined) {
    // Only pay attention to encoding if it's a string. This
    // prevents accidentally sending in a number that would
    // be interpretted as a start offset.
    return typeof encoding === 'string'
      ? createBuffer(that, size).fill(fill, encoding)
      : createBuffer(that, size).fill(fill)
  }
  return createBuffer(that, size)
}

/**
 * Creates a new filled Buffer instance.
 * alloc(size[, fill[, encoding]])
 **/
Buffer.alloc = function (size, fill, encoding) {
  return alloc(null, size, fill, encoding)
}

function allocUnsafe (that, size) {
  assertSize(size)
  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
  if (!Buffer.TYPED_ARRAY_SUPPORT) {
    for (var i = 0; i < size; ++i) {
      that[i] = 0
    }
  }
  return that
}

/**
 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
 * */
Buffer.allocUnsafe = function (size) {
  return allocUnsafe(null, size)
}
/**
 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
 */
Buffer.allocUnsafeSlow = function (size) {
  return allocUnsafe(null, size)
}

function fromString (that, string, encoding) {
  if (typeof encoding !== 'string' || encoding === '') {
    encoding = 'utf8'
  }

  if (!Buffer.isEncoding(encoding)) {
    throw new TypeError('"encoding" must be a valid string encoding')
  }

  var length = byteLength(string, encoding) | 0
  that = createBuffer(that, length)

  var actual = that.write(string, encoding)

  if (actual !== length) {
    // Writing a hex string, for example, that contains invalid characters will
    // cause everything after the first invalid character to be ignored. (e.g.
    // 'abxxcd' will be treated as 'ab')
    that = that.slice(0, actual)
  }

  return that
}

function fromArrayLike (that, array) {
  var length = array.length < 0 ? 0 : checked(array.length) | 0
  that = createBuffer(that, length)
  for (var i = 0; i < length; i += 1) {
    that[i] = array[i] & 255
  }
  return that
}

function fromArrayBuffer (that, array, byteOffset, length) {
  array.byteLength // this throws if `array` is not a valid ArrayBuffer

  if (byteOffset < 0 || array.byteLength < byteOffset) {
    throw new RangeError('\'offset\' is out of bounds')
  }

  if (array.byteLength < byteOffset + (length || 0)) {
    throw new RangeError('\'length\' is out of bounds')
  }

  if (byteOffset === undefined && length === undefined) {
    array = new Uint8Array(array)
  } else if (length === undefined) {
    array = new Uint8Array(array, byteOffset)
  } else {
    array = new Uint8Array(array, byteOffset, length)
  }

  if (Buffer.TYPED_ARRAY_SUPPORT) {
    // Return an augmented `Uint8Array` instance, for best performance
    that = array
    that.__proto__ = Buffer.prototype
  } else {
    // Fallback: Return an object instance of the Buffer class
    that = fromArrayLike(that, array)
  }
  return that
}

function fromObject (that, obj) {
  if (Buffer.isBuffer(obj)) {
    var len = checked(obj.length) | 0
    that = createBuffer(that, len)

    if (that.length === 0) {
      return that
    }

    obj.copy(that, 0, 0, len)
    return that
  }

  if (obj) {
    if ((typeof ArrayBuffer !== 'undefined' &&
        obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
      if (typeof obj.length !== 'number' || isnan(obj.length)) {
        return createBuffer(that, 0)
      }
      return fromArrayLike(that, obj)
    }

    if (obj.type === 'Buffer' && isArray(obj.data)) {
      return fromArrayLike(that, obj.data)
    }
  }

  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
}

function checked (length) {
  // Note: cannot use `length < kMaxLength()` here because that fails when
  // length is NaN (which is otherwise coerced to zero.)
  if (length >= kMaxLength()) {
    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
                         'size: 0x' + kMaxLength().toString(16) + ' bytes')
  }
  return length | 0
}

function SlowBuffer (length) {
  if (+length != length) { // eslint-disable-line eqeqeq
    length = 0
  }
  return Buffer.alloc(+length)
}

Buffer.isBuffer = function isBuffer (b) {
  return !!(b != null && b._isBuffer)
}

Buffer.compare = function compare (a, b) {
  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
    throw new TypeError('Arguments must be Buffers')
  }

  if (a === b) return 0

  var x = a.length
  var y = b.length

  for (var i = 0, len = Math.min(x, y); i < len; ++i) {
    if (a[i] !== b[i]) {
      x = a[i]
      y = b[i]
      break
    }
  }

  if (x < y) return -1
  if (y < x) return 1
  return 0
}

Buffer.isEncoding = function isEncoding (encoding) {
  switch (String(encoding).toLowerCase()) {
    case 'hex':
    case 'utf8':
    case 'utf-8':
    case 'ascii':
    case 'latin1':
    case 'binary':
    case 'base64':
    case 'ucs2':
    case 'ucs-2':
    case 'utf16le':
    case 'utf-16le':
      return true
    default:
      return false
  }
}

Buffer.concat = function concat (list, length) {
  if (!isArray(list)) {
    throw new TypeError('"list" argument must be an Array of Buffers')
  }

  if (list.length === 0) {
    return Buffer.alloc(0)
  }

  var i
  if (length === undefined) {
    length = 0
    for (i = 0; i < list.length; ++i) {
      length += list[i].length
    }
  }

  var buffer = Buffer.allocUnsafe(length)
  var pos = 0
  for (i = 0; i < list.length; ++i) {
    var buf = list[i]
    if (!Buffer.isBuffer(buf)) {
      throw new TypeError('"list" argument must be an Array of Buffers')
    }
    buf.copy(buffer, pos)
    pos += buf.length
  }
  return buffer
}

function byteLength (string, encoding) {
  if (Buffer.isBuffer(string)) {
    return string.length
  }
  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
      (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
    return string.byteLength
  }
  if (typeof string !== 'string') {
    string = '' + string
  }

  var len = string.length
  if (len === 0) return 0

  // Use a for loop to avoid recursion
  var loweredCase = false
  for (;;) {
    switch (encoding) {
      case 'ascii':
      case 'latin1':
      case 'binary':
        return len
      case 'utf8':
      case 'utf-8':
      case undefined:
        return utf8ToBytes(string).length
      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return len * 2
      case 'hex':
        return len >>> 1
      case 'base64':
        return base64ToBytes(string).length
      default:
        if (loweredCase) return utf8ToBytes(string).length // assume utf8
        encoding = ('' + encoding).toLowerCase()
        loweredCase = true
    }
  }
}
Buffer.byteLength = byteLength

function slowToString (encoding, start, end) {
  var loweredCase = false

  // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
  // property of a typed array.

  // This behaves neither like String nor Uint8Array in that we set start/end
  // to their upper/lower bounds if the value passed is out of range.
  // undefined is handled specially as per ECMA-262 6th Edition,
  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
  if (start === undefined || start < 0) {
    start = 0
  }
  // Return early if start > this.length. Done here to prevent potential uint32
  // coercion fail below.
  if (start > this.length) {
    return ''
  }

  if (end === undefined || end > this.length) {
    end = this.length
  }

  if (end <= 0) {
    return ''
  }

  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
  end >>>= 0
  start >>>= 0

  if (end <= start) {
    return ''
  }

  if (!encoding) encoding = 'utf8'

  while (true) {
    switch (encoding) {
      case 'hex':
        return hexSlice(this, start, end)

      case 'utf8':
      case 'utf-8':
        return utf8Slice(this, start, end)

      case 'ascii':
        return asciiSlice(this, start, end)

      case 'latin1':
      case 'binary':
        return latin1Slice(this, start, end)

      case 'base64':
        return base64Slice(this, start, end)

      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return utf16leSlice(this, start, end)

      default:
        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
        encoding = (encoding + '').toLowerCase()
        loweredCase = true
    }
  }
}

// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
// Buffer instances.
Buffer.prototype._isBuffer = true

function swap (b, n, m) {
  var i = b[n]
  b[n] = b[m]
  b[m] = i
}

Buffer.prototype.swap16 = function swap16 () {
  var len = this.length
  if (len % 2 !== 0) {
    throw new RangeError('Buffer size must be a multiple of 16-bits')
  }
  for (var i = 0; i < len; i += 2) {
    swap(this, i, i + 1)
  }
  return this
}

Buffer.prototype.swap32 = function swap32 () {
  var len = this.length
  if (len % 4 !== 0) {
    throw new RangeError('Buffer size must be a multiple of 32-bits')
  }
  for (var i = 0; i < len; i += 4) {
    swap(this, i, i + 3)
    swap(this, i + 1, i + 2)
  }
  return this
}

Buffer.prototype.swap64 = function swap64 () {
  var len = this.length
  if (len % 8 !== 0) {
    throw new RangeError('Buffer size must be a multiple of 64-bits')
  }
  for (var i = 0; i < len; i += 8) {
    swap(this, i, i + 7)
    swap(this, i + 1, i + 6)
    swap(this, i + 2, i + 5)
    swap(this, i + 3, i + 4)
  }
  return this
}

Buffer.prototype.toString = function toString () {
  var length = this.length | 0
  if (length === 0) return ''
  if (arguments.length === 0) return utf8Slice(this, 0, length)
  return slowToString.apply(this, arguments)
}

Buffer.prototype.equals = function equals (b) {
  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
  if (this === b) return true
  return Buffer.compare(this, b) === 0
}

Buffer.prototype.inspect = function inspect () {
  var str = ''
  var max = exports.INSPECT_MAX_BYTES
  if (this.length > 0) {
    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
    if (this.length > max) str += ' ... '
  }
  return '<Buffer ' + str + '>'
}

Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
  if (!Buffer.isBuffer(target)) {
    throw new TypeError('Argument must be a Buffer')
  }

  if (start === undefined) {
    start = 0
  }
  if (end === undefined) {
    end = target ? target.length : 0
  }
  if (thisStart === undefined) {
    thisStart = 0
  }
  if (thisEnd === undefined) {
    thisEnd = this.length
  }

  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
    throw new RangeError('out of range index')
  }

  if (thisStart >= thisEnd && start >= end) {
    return 0
  }
  if (thisStart >= thisEnd) {
    return -1
  }
  if (start >= end) {
    return 1
  }

  start >>>= 0
  end >>>= 0
  thisStart >>>= 0
  thisEnd >>>= 0

  if (this === target) return 0

  var x = thisEnd - thisStart
  var y = end - start
  var len = Math.min(x, y)

  var thisCopy = this.slice(thisStart, thisEnd)
  var targetCopy = target.slice(start, end)

  for (var i = 0; i < len; ++i) {
    if (thisCopy[i] !== targetCopy[i]) {
      x = thisCopy[i]
      y = targetCopy[i]
      break
    }
  }

  if (x < y) return -1
  if (y < x) return 1
  return 0
}

// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
  // Empty buffer means no match
  if (buffer.length === 0) return -1

  // Normalize byteOffset
  if (typeof byteOffset === 'string') {
    encoding = byteOffset
    byteOffset = 0
  } else if (byteOffset > 0x7fffffff) {
    byteOffset = 0x7fffffff
  } else if (byteOffset < -0x80000000) {
    byteOffset = -0x80000000
  }
  byteOffset = +byteOffset  // Coerce to Number.
  if (isNaN(byteOffset)) {
    // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
    byteOffset = dir ? 0 : (buffer.length - 1)
  }

  // Normalize byteOffset: negative offsets start from the end of the buffer
  if (byteOffset < 0) byteOffset = buffer.length + byteOffset
  if (byteOffset >= buffer.length) {
    if (dir) return -1
    else byteOffset = buffer.length - 1
  } else if (byteOffset < 0) {
    if (dir) byteOffset = 0
    else return -1
  }

  // Normalize val
  if (typeof val === 'string') {
    val = Buffer.from(val, encoding)
  }

  // Finally, search either indexOf (if dir is true) or lastIndexOf
  if (Buffer.isBuffer(val)) {
    // Special case: looking for empty string/buffer always fails
    if (val.length === 0) {
      return -1
    }
    return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
  } else if (typeof val === 'number') {
    val = val & 0xFF // Search for a byte value [0-255]
    if (Buffer.TYPED_ARRAY_SUPPORT &&
        typeof Uint8Array.prototype.indexOf === 'function') {
      if (dir) {
        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
      } else {
        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
      }
    }
    return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
  }

  throw new TypeError('val must be string, number or Buffer')
}

function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
  var indexSize = 1
  var arrLength = arr.length
  var valLength = val.length

  if (encoding !== undefined) {
    encoding = String(encoding).toLowerCase()
    if (encoding === 'ucs2' || encoding === 'ucs-2' ||
        encoding === 'utf16le' || encoding === 'utf-16le') {
      if (arr.length < 2 || val.length < 2) {
        return -1
      }
      indexSize = 2
      arrLength /= 2
      valLength /= 2
      byteOffset /= 2
    }
  }

  function read (buf, i) {
    if (indexSize === 1) {
      return buf[i]
    } else {
      return buf.readUInt16BE(i * indexSize)
    }
  }

  var i
  if (dir) {
    var foundIndex = -1
    for (i = byteOffset; i < arrLength; i++) {
      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
        if (foundIndex === -1) foundIndex = i
        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
      } else {
        if (foundIndex !== -1) i -= i - foundIndex
        foundIndex = -1
      }
    }
  } else {
    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
    for (i = byteOffset; i >= 0; i--) {
      var found = true
      for (var j = 0; j < valLength; j++) {
        if (read(arr, i + j) !== read(val, j)) {
          found = false
          break
        }
      }
      if (found) return i
    }
  }

  return -1
}

Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
  return this.indexOf(val, byteOffset, encoding) !== -1
}

Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
  return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
}

Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
  return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}

function hexWrite (buf, string, offset, length) {
  offset = Number(offset) || 0
  var remaining = buf.length - offset
  if (!length) {
    length = remaining
  } else {
    length = Number(length)
    if (length > remaining) {
      length = remaining
    }
  }

  // must be an even number of digits
  var strLen = string.length
  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')

  if (length > strLen / 2) {
    length = strLen / 2
  }
  for (var i = 0; i < length; ++i) {
    var parsed = parseInt(string.substr(i * 2, 2), 16)
    if (isNaN(parsed)) return i
    buf[offset + i] = parsed
  }
  return i
}

function utf8Write (buf, string, offset, length) {
  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
}

function asciiWrite (buf, string, offset, length) {
  return blitBuffer(asciiToBytes(string), buf, offset, length)
}

function latin1Write (buf, string, offset, length) {
  return asciiWrite(buf, string, offset, length)
}

function base64Write (buf, string, offset, length) {
  return blitBuffer(base64ToBytes(string), buf, offset, length)
}

function ucs2Write (buf, string, offset, length) {
  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
}

Buffer.prototype.write = function write (string, offset, length, encoding) {
  // Buffer#write(string)
  if (offset === undefined) {
    encoding = 'utf8'
    length = this.length
    offset = 0
  // Buffer#write(string, encoding)
  } else if (length === undefined && typeof offset === 'string') {
    encoding = offset
    length = this.length
    offset = 0
  // Buffer#write(string, offset[, length][, encoding])
  } else if (isFinite(offset)) {
    offset = offset | 0
    if (isFinite(length)) {
      length = length | 0
      if (encoding === undefined) encoding = 'utf8'
    } else {
      encoding = length
      length = undefined
    }
  // legacy write(string, encoding, offset, length) - remove in v0.13
  } else {
    throw new Error(
      'Buffer.write(string, encoding, offset[, length]) is no longer supported'
    )
  }

  var remaining = this.length - offset
  if (length === undefined || length > remaining) length = remaining

  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
    throw new RangeError('Attempt to write outside buffer bounds')
  }

  if (!encoding) encoding = 'utf8'

  var loweredCase = false
  for (;;) {
    switch (encoding) {
      case 'hex':
        return hexWrite(this, string, offset, length)

      case 'utf8':
      case 'utf-8':
        return utf8Write(this, string, offset, length)

      case 'ascii':
        return asciiWrite(this, string, offset, length)

      case 'latin1':
      case 'binary':
        return latin1Write(this, string, offset, length)

      case 'base64':
        // Warning: maxLength not taken into account in base64Write
        return base64Write(this, string, offset, length)

      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return ucs2Write(this, string, offset, length)

      default:
        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
        encoding = ('' + encoding).toLowerCase()
        loweredCase = true
    }
  }
}

Buffer.prototype.toJSON = function toJSON () {
  return {
    type: 'Buffer',
    data: Array.prototype.slice.call(this._arr || this, 0)
  }
}

function base64Slice (buf, start, end) {
  if (start === 0 && end === buf.length) {
    return base64.fromByteArray(buf)
  } else {
    return base64.fromByteArray(buf.slice(start, end))
  }
}

function utf8Slice (buf, start, end) {
  end = Math.min(buf.length, end)
  var res = []

  var i = start
  while (i < end) {
    var firstByte = buf[i]
    var codePoint = null
    var bytesPerSequence = (firstByte > 0xEF) ? 4
      : (firstByte > 0xDF) ? 3
      : (firstByte > 0xBF) ? 2
      : 1

    if (i + bytesPerSequence <= end) {
      var secondByte, thirdByte, fourthByte, tempCodePoint

      switch (bytesPerSequence) {
        case 1:
          if (firstByte < 0x80) {
            codePoint = firstByte
          }
          break
        case 2:
          secondByte = buf[i + 1]
          if ((secondByte & 0xC0) === 0x80) {
            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
            if (tempCodePoint > 0x7F) {
              codePoint = tempCodePoint
            }
          }
          break
        case 3:
          secondByte = buf[i + 1]
          thirdByte = buf[i + 2]
          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
              codePoint = tempCodePoint
            }
          }
          break
        case 4:
          secondByte = buf[i + 1]
          thirdByte = buf[i + 2]
          fourthByte = buf[i + 3]
          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
              codePoint = tempCodePoint
            }
          }
      }
    }

    if (codePoint === null) {
      // we did not generate a valid codePoint so insert a
      // replacement char (U+FFFD) and advance only 1 byte
      codePoint = 0xFFFD
      bytesPerSequence = 1
    } else if (codePoint > 0xFFFF) {
      // encode to utf16 (surrogate pair dance)
      codePoint -= 0x10000
      res.push(codePoint >>> 10 & 0x3FF | 0xD800)
      codePoint = 0xDC00 | codePoint & 0x3FF
    }

    res.push(codePoint)
    i += bytesPerSequence
  }

  return decodeCodePointsArray(res)
}

// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
var MAX_ARGUMENTS_LENGTH = 0x1000

function decodeCodePointsArray (codePoints) {
  var len = codePoints.length
  if (len <= MAX_ARGUMENTS_LENGTH) {
    return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
  }

  // Decode in chunks to avoid "call stack size exceeded".
  var res = ''
  var i = 0
  while (i < len) {
    res += String.fromCharCode.apply(
      String,
      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
    )
  }
  return res
}

function asciiSlice (buf, start, end) {
  var ret = ''
  end = Math.min(buf.length, end)

  for (var i = start; i < end; ++i) {
    ret += String.fromCharCode(buf[i] & 0x7F)
  }
  return ret
}

function latin1Slice (buf, start, end) {
  var ret = ''
  end = Math.min(buf.length, end)

  for (var i = start; i < end; ++i) {
    ret += String.fromCharCode(buf[i])
  }
  return ret
}

function hexSlice (buf, start, end) {
  var len = buf.length

  if (!start || start < 0) start = 0
  if (!end || end < 0 || end > len) end = len

  var out = ''
  for (var i = start; i < end; ++i) {
    out += toHex(buf[i])
  }
  return out
}

function utf16leSlice (buf, start, end) {
  var bytes = buf.slice(start, end)
  var res = ''
  for (var i = 0; i < bytes.length; i += 2) {
    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
  }
  return res
}

Buffer.prototype.slice = function slice (start, end) {
  var len = this.length
  start = ~~start
  end = end === undefined ? len : ~~end

  if (start < 0) {
    start += len
    if (start < 0) start = 0
  } else if (start > len) {
    start = len
  }

  if (end < 0) {
    end += len
    if (end < 0) end = 0
  } else if (end > len) {
    end = len
  }

  if (end < start) end = start

  var newBuf
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    newBuf = this.subarray(start, end)
    newBuf.__proto__ = Buffer.prototype
  } else {
    var sliceLen = end - start
    newBuf = new Buffer(sliceLen, undefined)
    for (var i = 0; i < sliceLen; ++i) {
      newBuf[i] = this[i + start]
    }
  }

  return newBuf
}

/*
 * Need to make sure that buffer isn't trying to write out of bounds.
 */
function checkOffset (offset, ext, length) {
  if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
}

Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) checkOffset(offset, byteLength, this.length)

  var val = this[offset]
  var mul = 1
  var i = 0
  while (++i < byteLength && (mul *= 0x100)) {
    val += this[offset + i] * mul
  }

  return val
}

Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) {
    checkOffset(offset, byteLength, this.length)
  }

  var val = this[offset + --byteLength]
  var mul = 1
  while (byteLength > 0 && (mul *= 0x100)) {
    val += this[offset + --byteLength] * mul
  }

  return val
}

Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 1, this.length)
  return this[offset]
}

Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 2, this.length)
  return this[offset] | (this[offset + 1] << 8)
}

Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 2, this.length)
  return (this[offset] << 8) | this[offset + 1]
}

Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)

  return ((this[offset]) |
      (this[offset + 1] << 8) |
      (this[offset + 2] << 16)) +
      (this[offset + 3] * 0x1000000)
}

Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)

  return (this[offset] * 0x1000000) +
    ((this[offset + 1] << 16) |
    (this[offset + 2] << 8) |
    this[offset + 3])
}

Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) checkOffset(offset, byteLength, this.length)

  var val = this[offset]
  var mul = 1
  var i = 0
  while (++i < byteLength && (mul *= 0x100)) {
    val += this[offset + i] * mul
  }
  mul *= 0x80

  if (val >= mul) val -= Math.pow(2, 8 * byteLength)

  return val
}

Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) checkOffset(offset, byteLength, this.length)

  var i = byteLength
  var mul = 1
  var val = this[offset + --i]
  while (i > 0 && (mul *= 0x100)) {
    val += this[offset + --i] * mul
  }
  mul *= 0x80

  if (val >= mul) val -= Math.pow(2, 8 * byteLength)

  return val
}

Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 1, this.length)
  if (!(this[offset] & 0x80)) return (this[offset])
  return ((0xff - this[offset] + 1) * -1)
}

Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 2, this.length)
  var val = this[offset] | (this[offset + 1] << 8)
  return (val & 0x8000) ? val | 0xFFFF0000 : val
}

Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 2, this.length)
  var val = this[offset + 1] | (this[offset] << 8)
  return (val & 0x8000) ? val | 0xFFFF0000 : val
}

Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)

  return (this[offset]) |
    (this[offset + 1] << 8) |
    (this[offset + 2] << 16) |
    (this[offset + 3] << 24)
}

Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)

  return (this[offset] << 24) |
    (this[offset + 1] << 16) |
    (this[offset + 2] << 8) |
    (this[offset + 3])
}

Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)
  return ieee754.read(this, offset, true, 23, 4)
}

Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 4, this.length)
  return ieee754.read(this, offset, false, 23, 4)
}

Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 8, this.length)
  return ieee754.read(this, offset, true, 52, 8)
}

Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
  if (!noAssert) checkOffset(offset, 8, this.length)
  return ieee754.read(this, offset, false, 52, 8)
}

function checkInt (buf, value, offset, ext, max, min) {
  if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
  if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
  if (offset + ext > buf.length) throw new RangeError('Index out of range')
}

Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
  value = +value
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) {
    var maxBytes = Math.pow(2, 8 * byteLength) - 1
    checkInt(this, value, offset, byteLength, maxBytes, 0)
  }

  var mul = 1
  var i = 0
  this[offset] = value & 0xFF
  while (++i < byteLength && (mul *= 0x100)) {
    this[offset + i] = (value / mul) & 0xFF
  }

  return offset + byteLength
}

Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
  value = +value
  offset = offset | 0
  byteLength = byteLength | 0
  if (!noAssert) {
    var maxBytes = Math.pow(2, 8 * byteLength) - 1
    checkInt(this, value, offset, byteLength, maxBytes, 0)
  }

  var i = byteLength - 1
  var mul = 1
  this[offset + i] = value & 0xFF
  while (--i >= 0 && (mul *= 0x100)) {
    this[offset + i] = (value / mul) & 0xFF
  }

  return offset + byteLength
}

Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
  this[offset] = (value & 0xff)
  return offset + 1
}

function objectWriteUInt16 (buf, value, offset, littleEndian) {
  if (value < 0) value = 0xffff + value + 1
  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
      (littleEndian ? i : 1 - i) * 8
  }
}

Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value & 0xff)
    this[offset + 1] = (value >>> 8)
  } else {
    objectWriteUInt16(this, value, offset, true)
  }
  return offset + 2
}

Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value >>> 8)
    this[offset + 1] = (value & 0xff)
  } else {
    objectWriteUInt16(this, value, offset, false)
  }
  return offset + 2
}

function objectWriteUInt32 (buf, value, offset, littleEndian) {
  if (value < 0) value = 0xffffffff + value + 1
  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
  }
}

Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset + 3] = (value >>> 24)
    this[offset + 2] = (value >>> 16)
    this[offset + 1] = (value >>> 8)
    this[offset] = (value & 0xff)
  } else {
    objectWriteUInt32(this, value, offset, true)
  }
  return offset + 4
}

Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value >>> 24)
    this[offset + 1] = (value >>> 16)
    this[offset + 2] = (value >>> 8)
    this[offset + 3] = (value & 0xff)
  } else {
    objectWriteUInt32(this, value, offset, false)
  }
  return offset + 4
}

Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) {
    var limit = Math.pow(2, 8 * byteLength - 1)

    checkInt(this, value, offset, byteLength, limit - 1, -limit)
  }

  var i = 0
  var mul = 1
  var sub = 0
  this[offset] = value & 0xFF
  while (++i < byteLength && (mul *= 0x100)) {
    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
      sub = 1
    }
    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
  }

  return offset + byteLength
}

Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) {
    var limit = Math.pow(2, 8 * byteLength - 1)

    checkInt(this, value, offset, byteLength, limit - 1, -limit)
  }

  var i = byteLength - 1
  var mul = 1
  var sub = 0
  this[offset + i] = value & 0xFF
  while (--i >= 0 && (mul *= 0x100)) {
    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
      sub = 1
    }
    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
  }

  return offset + byteLength
}

Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
  if (value < 0) value = 0xff + value + 1
  this[offset] = (value & 0xff)
  return offset + 1
}

Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value & 0xff)
    this[offset + 1] = (value >>> 8)
  } else {
    objectWriteUInt16(this, value, offset, true)
  }
  return offset + 2
}

Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value >>> 8)
    this[offset + 1] = (value & 0xff)
  } else {
    objectWriteUInt16(this, value, offset, false)
  }
  return offset + 2
}

Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value & 0xff)
    this[offset + 1] = (value >>> 8)
    this[offset + 2] = (value >>> 16)
    this[offset + 3] = (value >>> 24)
  } else {
    objectWriteUInt32(this, value, offset, true)
  }
  return offset + 4
}

Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
  value = +value
  offset = offset | 0
  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
  if (value < 0) value = 0xffffffff + value + 1
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value >>> 24)
    this[offset + 1] = (value >>> 16)
    this[offset + 2] = (value >>> 8)
    this[offset + 3] = (value & 0xff)
  } else {
    objectWriteUInt32(this, value, offset, false)
  }
  return offset + 4
}

function checkIEEE754 (buf, value, offset, ext, max, min) {
  if (offset + ext > buf.length) throw new RangeError('Index out of range')
  if (offset < 0) throw new RangeError('Index out of range')
}

function writeFloat (buf, value, offset, littleEndian, noAssert) {
  if (!noAssert) {
    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
  }
  ieee754.write(buf, value, offset, littleEndian, 23, 4)
  return offset + 4
}

Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
  return writeFloat(this, value, offset, true, noAssert)
}

Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
  return writeFloat(this, value, offset, false, noAssert)
}

function writeDouble (buf, value, offset, littleEndian, noAssert) {
  if (!noAssert) {
    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
  }
  ieee754.write(buf, value, offset, littleEndian, 52, 8)
  return offset + 8
}

Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
  return writeDouble(this, value, offset, true, noAssert)
}

Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
  return writeDouble(this, value, offset, false, noAssert)
}

// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
  if (!start) start = 0
  if (!end && end !== 0) end = this.length
  if (targetStart >= target.length) targetStart = target.length
  if (!targetStart) targetStart = 0
  if (end > 0 && end < start) end = start

  // Copy 0 bytes; we're done
  if (end === start) return 0
  if (target.length === 0 || this.length === 0) return 0

  // Fatal error conditions
  if (targetStart < 0) {
    throw new RangeError('targetStart out of bounds')
  }
  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
  if (end < 0) throw new RangeError('sourceEnd out of bounds')

  // Are we oob?
  if (end > this.length) end = this.length
  if (target.length - targetStart < end - start) {
    end = target.length - targetStart + start
  }

  var len = end - start
  var i

  if (this === target && start < targetStart && targetStart < end) {
    // descending copy from end
    for (i = len - 1; i >= 0; --i) {
      target[i + targetStart] = this[i + start]
    }
  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
    // ascending copy from start
    for (i = 0; i < len; ++i) {
      target[i + targetStart] = this[i + start]
    }
  } else {
    Uint8Array.prototype.set.call(
      target,
      this.subarray(start, start + len),
      targetStart
    )
  }

  return len
}

// Usage:
//    buffer.fill(number[, offset[, end]])
//    buffer.fill(buffer[, offset[, end]])
//    buffer.fill(string[, offset[, end]][, encoding])
Buffer.prototype.fill = function fill (val, start, end, encoding) {
  // Handle string cases:
  if (typeof val === 'string') {
    if (typeof start === 'string') {
      encoding = start
      start = 0
      end = this.length
    } else if (typeof end === 'string') {
      encoding = end
      end = this.length
    }
    if (val.length === 1) {
      var code = val.charCodeAt(0)
      if (code < 256) {
        val = code
      }
    }
    if (encoding !== undefined && typeof encoding !== 'string') {
      throw new TypeError('encoding must be a string')
    }
    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
      throw new TypeError('Unknown encoding: ' + encoding)
    }
  } else if (typeof val === 'number') {
    val = val & 255
  }

  // Invalid ranges are not set to a default, so can range check early.
  if (start < 0 || this.length < start || this.length < end) {
    throw new RangeError('Out of range index')
  }

  if (end <= start) {
    return this
  }

  start = start >>> 0
  end = end === undefined ? this.length : end >>> 0

  if (!val) val = 0

  var i
  if (typeof val === 'number') {
    for (i = start; i < end; ++i) {
      this[i] = val
    }
  } else {
    var bytes = Buffer.isBuffer(val)
      ? val
      : utf8ToBytes(new Buffer(val, encoding).toString())
    var len = bytes.length
    for (i = 0; i < end - start; ++i) {
      this[i + start] = bytes[i % len]
    }
  }

  return this
}

// HELPER FUNCTIONS
// ================

var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g

function base64clean (str) {
  // Node strips out invalid characters like \n and \t from the string, base64-js does not
  str = stringtrim(str).replace(INVALID_BASE64_RE, '')
  // Node converts strings with length < 2 to ''
  if (str.length < 2) return ''
  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
  while (str.length % 4 !== 0) {
    str = str + '='
  }
  return str
}

function stringtrim (str) {
  if (str.trim) return str.trim()
  return str.replace(/^\s+|\s+$/g, '')
}

function toHex (n) {
  if (n < 16) return '0' + n.toString(16)
  return n.toString(16)
}

function utf8ToBytes (string, units) {
  units = units || Infinity
  var codePoint
  var length = string.length
  var leadSurrogate = null
  var bytes = []

  for (var i = 0; i < length; ++i) {
    codePoint = string.charCodeAt(i)

    // is surrogate component
    if (codePoint > 0xD7FF && codePoint < 0xE000) {
      // last char was a lead
      if (!leadSurrogate) {
        // no lead yet
        if (codePoint > 0xDBFF) {
          // unexpected trail
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
          continue
        } else if (i + 1 === length) {
          // unpaired lead
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
          continue
        }

        // valid lead
        leadSurrogate = codePoint

        continue
      }

      // 2 leads in a row
      if (codePoint < 0xDC00) {
        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
        leadSurrogate = codePoint
        continue
      }

      // valid surrogate pair
      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
    } else if (leadSurrogate) {
      // valid bmp char, but last char was a lead
      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
    }

    leadSurrogate = null

    // encode utf8
    if (codePoint < 0x80) {
      if ((units -= 1) < 0) break
      bytes.push(codePoint)
    } else if (codePoint < 0x800) {
      if ((units -= 2) < 0) break
      bytes.push(
        codePoint >> 0x6 | 0xC0,
        codePoint & 0x3F | 0x80
      )
    } else if (codePoint < 0x10000) {
      if ((units -= 3) < 0) break
      bytes.push(
        codePoint >> 0xC | 0xE0,
        codePoint >> 0x6 & 0x3F | 0x80,
        codePoint & 0x3F | 0x80
      )
    } else if (codePoint < 0x110000) {
      if ((units -= 4) < 0) break
      bytes.push(
        codePoint >> 0x12 | 0xF0,
        codePoint >> 0xC & 0x3F | 0x80,
        codePoint >> 0x6 & 0x3F | 0x80,
        codePoint & 0x3F | 0x80
      )
    } else {
      throw new Error('Invalid code point')
    }
  }

  return bytes
}

function asciiToBytes (str) {
  var byteArray = []
  for (var i = 0; i < str.length; ++i) {
    // Node's code seems to be doing this and not & 0x7F..
    byteArray.push(str.charCodeAt(i) & 0xFF)
  }
  return byteArray
}

function utf16leToBytes (str, units) {
  var c, hi, lo
  var byteArray = []
  for (var i = 0; i < str.length; ++i) {
    if ((units -= 2) < 0) break

    c = str.charCodeAt(i)
    hi = c >> 8
    lo = c % 256
    byteArray.push(lo)
    byteArray.push(hi)
  }

  return byteArray
}

function base64ToBytes (str) {
  return base64.toByteArray(base64clean(str))
}

function blitBuffer (src, dst, offset, length) {
  for (var i = 0; i < length; ++i) {
    if ((i + offset >= dst.length) || (i >= src.length)) break
    dst[i + offset] = src[i]
  }
  return i
}

function isnan (val) {
  return val !== val // eslint-disable-line no-self-compare
}

/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(190)))

/***/ }),
/* 217 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray

var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array

var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
  lookup[i] = code[i]
  revLookup[code.charCodeAt(i)] = i
}

revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63

function placeHoldersCount (b64) {
  var len = b64.length
  if (len % 4 > 0) {
    throw new Error('Invalid string. Length must be a multiple of 4')
  }

  // the number of equal signs (place holders)
  // if there are two placeholders, than the two characters before it
  // represent one byte
  // if there is only one, then the three characters before it represent 2 bytes
  // this is just a cheap hack to not do indexOf twice
  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
}

function byteLength (b64) {
  // base64 is 4/3 + up to two characters of the original data
  return (b64.length * 3 / 4) - placeHoldersCount(b64)
}

function toByteArray (b64) {
  var i, l, tmp, placeHolders, arr
  var len = b64.length
  placeHolders = placeHoldersCount(b64)

  arr = new Arr((len * 3 / 4) - placeHolders)

  // if there are placeholders, only get up to the last complete 4 chars
  l = placeHolders > 0 ? len - 4 : len

  var L = 0

  for (i = 0; i < l; i += 4) {
    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
    arr[L++] = (tmp >> 16) & 0xFF
    arr[L++] = (tmp >> 8) & 0xFF
    arr[L++] = tmp & 0xFF
  }

  if (placeHolders === 2) {
    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
    arr[L++] = tmp & 0xFF
  } else if (placeHolders === 1) {
    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
    arr[L++] = (tmp >> 8) & 0xFF
    arr[L++] = tmp & 0xFF
  }

  return arr
}

function tripletToBase64 (num) {
  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
}

function encodeChunk (uint8, start, end) {
  var tmp
  var output = []
  for (var i = start; i < end; i += 3) {
    tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
    output.push(tripletToBase64(tmp))
  }
  return output.join('')
}

function fromByteArray (uint8) {
  var tmp
  var len = uint8.length
  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
  var output = ''
  var parts = []
  var maxChunkLength = 16383 // must be multiple of 3

  // go through the array every three bytes, we'll deal with trailing stuff later
  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
  }

  // pad the end with zeros, but make sure to not forget the extra bytes
  if (extraBytes === 1) {
    tmp = uint8[len - 1]
    output += lookup[tmp >> 2]
    output += lookup[(tmp << 4) & 0x3F]
    output += '=='
  } else if (extraBytes === 2) {
    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
    output += lookup[tmp >> 10]
    output += lookup[(tmp >> 4) & 0x3F]
    output += lookup[(tmp << 2) & 0x3F]
    output += '='
  }

  parts.push(output)

  return parts.join('')
}


/***/ }),
/* 218 */
/***/ (function(module, exports) {

exports.read = function (buffer, offset, isLE, mLen, nBytes) {
  var e, m
  var eLen = nBytes * 8 - mLen - 1
  var eMax = (1 << eLen) - 1
  var eBias = eMax >> 1
  var nBits = -7
  var i = isLE ? (nBytes - 1) : 0
  var d = isLE ? -1 : 1
  var s = buffer[offset + i]

  i += d

  e = s & ((1 << (-nBits)) - 1)
  s >>= (-nBits)
  nBits += eLen
  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}

  m = e & ((1 << (-nBits)) - 1)
  e >>= (-nBits)
  nBits += mLen
  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}

  if (e === 0) {
    e = 1 - eBias
  } else if (e === eMax) {
    return m ? NaN : ((s ? -1 : 1) * Infinity)
  } else {
    m = m + Math.pow(2, mLen)
    e = e - eBias
  }
  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
}

exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
  var e, m, c
  var eLen = nBytes * 8 - mLen - 1
  var eMax = (1 << eLen) - 1
  var eBias = eMax >> 1
  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
  var i = isLE ? 0 : (nBytes - 1)
  var d = isLE ? 1 : -1
  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0

  value = Math.abs(value)

  if (isNaN(value) || value === Infinity) {
    m = isNaN(value) ? 1 : 0
    e = eMax
  } else {
    e = Math.floor(Math.log(value) / Math.LN2)
    if (value * (c = Math.pow(2, -e)) < 1) {
      e--
      c *= 2
    }
    if (e + eBias >= 1) {
      value += rt / c
    } else {
      value += rt * Math.pow(2, 1 - eBias)
    }
    if (value * c >= 2) {
      e++
      c /= 2
    }

    if (e + eBias >= eMax) {
      m = 0
      e = eMax
    } else if (e + eBias >= 1) {
      m = (value * c - 1) * Math.pow(2, mLen)
      e = e + eBias
    } else {
      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
      e = 0
    }
  }

  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}

  e = (e << mLen) | m
  eLen += mLen
  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}

  buffer[offset + i - d] |= s * 128
}


/***/ }),
/* 219 */
/***/ (function(module, exports) {

var toString = {}.toString;

module.exports = Array.isArray || function (arr) {
  return toString.call(arr) == '[object Array]';
};


/***/ }),
/* 220 */
/***/ (function(module, exports) {



/***/ }),
/* 221 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var load = __webpack_require__(222)
var player = __webpack_require__(225)

/**
 * Load a soundfont instrument. It returns a promise that resolves to a
 * instrument object.
 *
 * The instrument object returned by the promise has the following properties:
 *
 * - name: the instrument name
 * - play: A function to play notes from the buffer with the signature
 * `play(note, time, duration, options)`
 *
 *
 * The valid options are:
 *
 * - `format`: the soundfont format. 'mp3' by default. Can be 'ogg'
 * - `soundfont`: the soundfont name. 'MusyngKite' by default. Can be 'FluidR3_GM'
 * - `nameToUrl` <Function>: a function to convert from instrument names to URL
 * - `destination`: by default Soundfont uses the `audioContext.destination` but you can override it.
 * - `gain`: the gain of the player (1 by default)
 * - `notes`: an array of the notes to decode. It can be an array of strings
 * with note names or an array of numbers with midi note numbers. This is a
 * performance option: since decoding mp3 is a cpu intensive process, you can limit
 * limit the number of notes you want and reduce the time to load the instrument.
 *
 * @param {AudioContext} ac - the audio context
 * @param {String} name - the instrument name. For example: 'acoustic_grand_piano'
 * @param {Object} options - (Optional) the same options as Soundfont.loadBuffers
 * @return {Promise}
 *
 * @example
 * var Soundfont = require('sounfont-player')
 * Soundfont.instrument('marimba').then(function (marimba) {
 *   marimba.play('C4')
 * })
 */
function instrument (ac, name, options) {
  if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) }
  var opts = options || {}
  var isUrl = opts.isSoundfontURL || isSoundfontURL
  var toUrl = opts.nameToUrl || nameToUrl
  var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format)

  return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) {
    var p = player(ac, buffers, opts).connect(ac.destination)
    p.url = url
    p.name = name
    return p
  })
}

function isSoundfontURL (name) {
  return /\.js(\?.*)?$/i.test(name)
}

/**
 * Given an instrument name returns a URL to to the Benjamin Gleitzman's
 * package of [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts)
 *
 * @param {String} name - instrument name
 * @param {String} soundfont - (Optional) the soundfont name. One of 'FluidR3_GM'
 * or 'MusyngKite' ('MusyngKite' by default)
 * @param {String} format - (Optional) Can be 'mp3' or 'ogg' (mp3 by default)
 * @returns {String} the Soundfont file url
 * @example
 * var Soundfont = require('soundfont-player')
 * Soundfont.nameToUrl('marimba', 'mp3')
 */
function nameToUrl (name, sf, format) {
  format = format === 'ogg' ? format : 'mp3'
  sf = sf === 'FluidR3_GM' ? sf : 'MusyngKite'
  return 'https://gleitz.github.io/midi-js-soundfonts/' + sf + '/' + name + '-' + format + '.js'
}

// In the 1.0.0 release it will be:
// var Soundfont = {}
var Soundfont = __webpack_require__(234)
Soundfont.instrument = instrument
Soundfont.nameToUrl = nameToUrl

if (typeof module === 'object' && module.exports) module.exports = Soundfont
if (typeof window !== 'undefined') window.Soundfont = Soundfont


/***/ }),
/* 222 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var base64 = __webpack_require__(223)
var fetch = __webpack_require__(224)

// Given a regex, return a function that test if against a string
function fromRegex (r) {
  return function (o) { return typeof o === 'string' && r.test(o) }
}
// Try to apply a prefix to a name
function prefix (pre, name) {
  return typeof pre === 'string' ? pre + name
    : typeof pre === 'function' ? pre(name)
    : name
}

/**
 * Load one or more audio files
 *
 *
 * Possible option keys:
 *
 * - __from__ {Function|String}: a function or string to convert from file names to urls.
 * If is a string it will be prefixed to the name:
 * `load(ac, 'snare.mp3', { from: 'http://audio.net/samples/' })`
 * If it's a function it receives the file name and should return the url as string.
 * - __only__ {Array} - when loading objects, if provided, only the given keys
 * will be included in the decoded object:
 * `load(ac, 'piano.json', { only: ['C2', 'D2'] })`
 *
 * @param {AudioContext} ac - the audio context
 * @param {Object} source - the object to be loaded
 * @param {Object} options - (Optional) the load options for that object
 * @param {Object} defaultValue - (Optional) the default value to return as
 * in a promise if not valid loader found
 */
function load (ac, source, options, defVal) {
  var loader =
    // Basic audio loading
      isArrayBuffer(source) ? loadArrayBuffer
    : isAudioFileName(source) ? loadAudioFile
    : isPromise(source) ? loadPromise
    // Compound objects
    : isArray(source) ? loadArrayData
    : isObject(source) ? loadObjectData
    : isJsonFileName(source) ? loadJsonFile
    // Base64 encoded audio
    : isBase64Audio(source) ? loadBase64Audio
    : isJsFileName(source) ? loadMidiJSFile
    : null

  var opts = options || {}
  return loader ? loader(ac, source, opts)
    : defVal ? Promise.resolve(defVal)
    : Promise.reject('Source not valid (' + source + ')')
}
load.fetch = fetch

// BASIC AUDIO LOADING
// ===================

// Load (decode) an array buffer
function isArrayBuffer (o) { return o instanceof ArrayBuffer }
function loadArrayBuffer (ac, array, options) {
  return new Promise(function (done, reject) {
    ac.decodeAudioData(array,
      function (buffer) { done(buffer) },
      function () { reject("Can't decode audio data (" + array.slice(0, 30) + '...)') }
    )
  })
}

// Load an audio filename
var isAudioFileName = fromRegex(/\.(mp3|wav|ogg)(\?.*)?$/i)
function loadAudioFile (ac, name, options) {
  var url = prefix(options.from, name)
  return load(ac, load.fetch(url, 'arraybuffer'), options)
}

// Load the result of a promise
function isPromise (o) { return o && typeof o.then === 'function' }
function loadPromise (ac, promise, options) {
  return promise.then(function (value) {
    return load(ac, value, options)
  })
}

// COMPOUND OBJECTS
// ================

// Try to load all the items of an array
var isArray = Array.isArray
function loadArrayData (ac, array, options) {
  return Promise.all(array.map(function (data) {
    return load(ac, data, options, data)
  }))
}

// Try to load all the values of a key/value object
function isObject (o) { return o && typeof o === 'object' }
function loadObjectData (ac, obj, options) {
  var dest = {}
  var promises = Object.keys(obj).map(function (key) {
    if (options.only && options.only.indexOf(key) === -1) return null
    var value = obj[key]
    return load(ac, value, options, value).then(function (audio) {
      dest[key] = audio
    })
  })
  return Promise.all(promises).then(function () { return dest })
}

// Load the content of a JSON file
var isJsonFileName = fromRegex(/\.json(\?.*)?$/i)
function loadJsonFile (ac, name, options) {
  var url = prefix(options.from, name)
  return load(ac, load.fetch(url, 'text').then(JSON.parse), options)
}

// BASE64 ENCODED FORMATS
// ======================

// Load strings with Base64 encoded audio
var isBase64Audio = fromRegex(/^data:audio/)
function loadBase64Audio (ac, source, options) {
  var i = source.indexOf(',')
  return load(ac, base64.decode(source.slice(i + 1)).buffer, options)
}

// Load .js files with MidiJS soundfont prerendered audio
var isJsFileName = fromRegex(/\.js(\?.*)?$/i)
function loadMidiJSFile (ac, name, options) {
  var url = prefix(options.from, name)
  return load(ac, load.fetch(url, 'text').then(midiJsToJson), options)
}

// convert a MIDI.js javascript soundfont file to json
function midiJsToJson (data) {
  var begin = data.indexOf('MIDI.Soundfont.')
  if (begin < 0) throw Error('Invalid MIDI.js Soundfont format')
  begin = data.indexOf('=', begin) + 2
  var end = data.lastIndexOf(',')
  return JSON.parse(data.slice(begin, end) + '}')
}

if (typeof module === 'object' && module.exports) module.exports = load
if (typeof window !== 'undefined') window.loadAudio = load


/***/ }),
/* 223 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


// DECODE UTILITIES
function b64ToUint6 (nChr) {
  return nChr > 64 && nChr < 91 ? nChr - 65
    : nChr > 96 && nChr < 123 ? nChr - 71
    : nChr > 47 && nChr < 58 ? nChr + 4
    : nChr === 43 ? 62
    : nChr === 47 ? 63
    : 0
}

// Decode Base64 to Uint8Array
// ---------------------------
function decode (sBase64, nBlocksSize) {
  var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, '')
  var nInLen = sB64Enc.length
  var nOutLen = nBlocksSize
    ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize
    : nInLen * 3 + 1 >> 2
  var taBytes = new Uint8Array(nOutLen)

  for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
    nMod4 = nInIdx & 3
    nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4
    if (nMod4 === 3 || nInLen - nInIdx === 1) {
      for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
        taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255
      }
      nUint24 = 0
    }
  }
  return taBytes
}

module.exports = { decode: decode }


/***/ }),
/* 224 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* global XMLHttpRequest */


/**
 * Given a url and a return type, returns a promise to the content of the url
 * Basically it wraps a XMLHttpRequest into a Promise
 *
 * @param {String} url
 * @param {String} type - can be 'text' or 'arraybuffer'
 * @return {Promise}
 */
module.exports = function (url, type) {
  return new Promise(function (done, reject) {
    var req = new XMLHttpRequest()
    if (type) req.responseType = type

    req.open('GET', url)
    req.onload = function () {
      req.status === 200 ? done(req.response) : reject(Error(req.statusText))
    }
    req.onerror = function () { reject(Error('Network Error')) }
    req.send()
  })
}


/***/ }),
/* 225 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var player = __webpack_require__(226)
var events = __webpack_require__(228)
var notes = __webpack_require__(229)
var scheduler = __webpack_require__(231)
var midi = __webpack_require__(232)

function SamplePlayer (ac, source, options) {
  return midi(scheduler(notes(events(player(ac, source, options)))))
}

if (typeof module === 'object' && module.exports) module.exports = SamplePlayer
if (typeof window !== 'undefined') window.SamplePlayer = SamplePlayer


/***/ }),
/* 226 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* global AudioBuffer */


var ADSR = __webpack_require__(227)

var EMPTY = {}
var DEFAULTS = {
  gain: 1,
  attack: 0.01,
  decay: 0.1,
  sustain: 0.9,
  release: 0.3,
  loop: false,
  cents: 0,
  loopStart: 0,
  loopEnd: 0
}

/**
 * Create a sample player.
 *
 * @param {AudioContext} ac - the audio context
 * @param {ArrayBuffer|Object<String,ArrayBuffer>} source
 * @param {Onject} options - (Optional) an options object
 * @return {player} the player
 * @example
 * var SamplePlayer = require('sample-player')
 * var ac = new AudioContext()
 * var snare = SamplePlayer(ac, <AudioBuffer>)
 * snare.play()
 */
function SamplePlayer (ac, source, options) {
  var connected = false
  var nextId = 0
  var tracked = {}
  var out = ac.createGain()
  out.gain.value = 1

  var opts = Object.assign({}, DEFAULTS, options)

  /**
   * @namespace
   */
  var player = { context: ac, out: out, opts: opts }
  if (source instanceof AudioBuffer) player.buffer = source
  else player.buffers = source

  /**
   * Start a sample buffer.
   *
   * The returned object has a function `stop(when)` to stop the sound.
   *
   * @param {String} name - the name of the buffer. If the source of the
   * SamplePlayer is one sample buffer, this parameter is not required
   * @param {Float} when - (Optional) when to start (current time if by default)
   * @param {Object} options - additional sample playing options
   * @return {AudioNode} an audio node with a `stop` function
   * @example
   * var sample = player(ac, <AudioBuffer>).connect(ac.destination)
   * sample.start()
   * sample.start(5, { gain: 0.7 }) // name not required since is only one AudioBuffer
   * @example
   * var drums = player(ac, { snare: <AudioBuffer>, kick: <AudioBuffer>, ... }).connect(ac.destination)
   * drums.start('snare')
   * drums.start('snare', 0, { gain: 0.3 })
   */
  player.start = function (name, when, options) {
    // if only one buffer, reorder arguments
    if (player.buffer && name !== null) return player.start(null, name, when)

    var buffer = name ? player.buffers[name] : player.buffer
    if (!buffer) {
      console.warn('Buffer ' + name + ' not found.')
      return
    } else if (!connected) {
      console.warn('SamplePlayer not connected to any node.')
      return
    }

    var opts = options || EMPTY
    when = Math.max(ac.currentTime, when || 0)
    player.emit('start', when, name, opts)
    var node = createNode(name, buffer, opts)
    node.id = track(name, node)
    node.env.start(when)
    node.source.start(when)
    player.emit('started', when, node.id, node)
    if (opts.duration) node.stop(when + opts.duration)
    return node
  }

  // NOTE: start will be override so we can't copy the function reference
  // this is obviously not a good design, so this code will be gone soon.
  /**
   * An alias for `player.start`
   * @see player.start
   * @since 0.3.0
   */
  player.play = function (name, when, options) {
    return player.start(name, when, options)
  }

  /**
   * Stop some or all samples
   *
   * @param {Float} when - (Optional) an absolute time in seconds (or currentTime
   * if not specified)
   * @param {Array} nodes - (Optional) an array of nodes or nodes ids to stop
   * @return {Array} an array of ids of the stoped samples
   *
   * @example
   * var longSound = player(ac, <AudioBuffer>).connect(ac.destination)
   * longSound.start(ac.currentTime)
   * longSound.start(ac.currentTime + 1)
   * longSound.start(ac.currentTime + 2)
   * longSound.stop(ac.currentTime + 3) // stop the three sounds
   */
  player.stop = function (when, ids) {
    var node
    ids = ids || Object.keys(tracked)
    return ids.map(function (id) {
      node = tracked[id]
      if (!node) return null
      node.stop(when)
      return node.id
    })
  }
  /**
   * Connect the player to a destination node
   *
   * @param {AudioNode} destination - the destination node
   * @return {AudioPlayer} the player
   * @chainable
   * @example
   * var sample = player(ac, <AudioBuffer>).connect(ac.destination)
   */
  player.connect = function (dest) {
    connected = true
    out.connect(dest)
    return player
  }

  player.emit = function (event, when, obj, opts) {
    if (player.onevent) player.onevent(event, when, obj, opts)
    var fn = player['on' + event]
    if (fn) fn(when, obj, opts)
  }

  return player

  // =============== PRIVATE FUNCTIONS ============== //

  function track (name, node) {
    node.id = nextId++
    tracked[node.id] = node
    node.source.onended = function () {
      var now = ac.currentTime
      node.source.disconnect()
      node.env.disconnect()
      node.disconnect()
      player.emit('ended', now, node.id, node)
    }
    return node.id
  }

  function createNode (name, buffer, options) {
    var node = ac.createGain()
    node.gain.value = 0 // the envelope will control the gain
    node.connect(out)

    node.env = envelope(ac, options, opts)
    node.env.connect(node.gain)

    node.source = ac.createBufferSource()
    node.source.buffer = buffer
    node.source.connect(node)
    node.source.loop = options.loop || opts.loop
    node.source.playbackRate.value = centsToRate(options.cents || opts.cents)
    node.source.loopStart = options.loopStart || opts.loopStart
    node.source.loopEnd = options.loopEnd || opts.loopEnd
    node.stop = function (when) {
      var time = when || ac.currentTime
      player.emit('stop', time, name)
      var stopAt = node.env.stop(time)
      node.source.stop(stopAt)
    }
    return node
  }
}

function isNum (x) { return typeof x === 'number' }
var PARAMS = ['attack', 'decay', 'sustain', 'release']
function envelope (ac, options, opts) {
  var env = ADSR(ac)
  var adsr = options.adsr || opts.adsr
  PARAMS.forEach(function (name, i) {
    if (adsr) env[name] = adsr[i]
    else env[name] = options[name] || opts[name]
  })
  env.value.value = isNum(options.gain) ? options.gain
    : isNum(opts.gain) ? opts.gain : 1
  return env
}

/*
 * Get playback rate for a given pitch change (in cents)
 * Basic [math](http://www.birdsoft.demon.co.uk/music/samplert.htm):
 * f2 = f1 * 2^( C / 1200 )
 */
function centsToRate (cents) { return cents ? Math.pow(2, cents / 1200) : 1 }

module.exports = SamplePlayer


/***/ }),
/* 227 */
/***/ (function(module, exports) {

module.exports = ADSR

function ADSR(audioContext){
  var node = audioContext.createGain()

  var voltage = node._voltage = getVoltage(audioContext)
  var value = scale(voltage)
  var startValue = scale(voltage)
  var endValue = scale(voltage)

  node._startAmount = scale(startValue)
  node._endAmount = scale(endValue)

  node._multiplier = scale(value)
  node._multiplier.connect(node)
  node._startAmount.connect(node)
  node._endAmount.connect(node)

  node.value = value.gain
  node.startValue = startValue.gain
  node.endValue = endValue.gain

  node.startValue.value = 0
  node.endValue.value = 0

  Object.defineProperties(node, props)
  return node
}

var props = {

  attack: { value: 0, writable: true },
  decay: { value: 0, writable: true },
  sustain: { value: 1, writable: true },
  release: {value: 0, writable: true },

  getReleaseDuration: {
    value: function(){
      return this.release
    }
  },

  start: {
    value: function(at){
      var target = this._multiplier.gain
      var startAmount = this._startAmount.gain
      var endAmount = this._endAmount.gain

      this._voltage.start(at)
      this._decayFrom = this._decayFrom = at+this.attack
      this._startedAt = at

      var sustain = this.sustain

      target.cancelScheduledValues(at)
      startAmount.cancelScheduledValues(at)
      endAmount.cancelScheduledValues(at)

      endAmount.setValueAtTime(0, at)

      if (this.attack){
        target.setValueAtTime(0, at)
        target.linearRampToValueAtTime(1, at + this.attack)

        startAmount.setValueAtTime(1, at)
        startAmount.linearRampToValueAtTime(0, at + this.attack)
      } else {
        target.setValueAtTime(1, at)
        startAmount.setValueAtTime(0, at)
      }

      if (this.decay){
        target.setTargetAtTime(sustain, this._decayFrom, getTimeConstant(this.decay))
      }
    }
  },

  stop: {
    value: function(at, isTarget){
      if (isTarget){
        at = at - this.release
      }

      var endTime = at + this.release
      if (this.release){

        var target = this._multiplier.gain
        var startAmount = this._startAmount.gain
        var endAmount = this._endAmount.gain

        target.cancelScheduledValues(at)
        startAmount.cancelScheduledValues(at)
        endAmount.cancelScheduledValues(at)

        var expFalloff = getTimeConstant(this.release)

        // truncate attack (required as linearRamp is removed by cancelScheduledValues)
        if (this.attack && at < this._decayFrom){
          var valueAtTime = getValue(0, 1, this._startedAt, this._decayFrom, at)
          target.linearRampToValueAtTime(valueAtTime, at)
          startAmount.linearRampToValueAtTime(1-valueAtTime, at)
          startAmount.setTargetAtTime(0, at, expFalloff)
        }

        endAmount.setTargetAtTime(1, at, expFalloff)
        target.setTargetAtTime(0, at, expFalloff)
      }

      this._voltage.stop(endTime)
      return endTime
    }
  },

  onended: {
    get: function(){
      return this._voltage.onended
    },
    set: function(value){
      this._voltage.onended = value
    }
  }

}

var flat = new Float32Array([1,1])
function getVoltage(context){
  var voltage = context.createBufferSource()
  var buffer = context.createBuffer(1, 2, context.sampleRate)
  buffer.getChannelData(0).set(flat)
  voltage.buffer = buffer
  voltage.loop = true
  return voltage
}

function scale(node){
  var gain = node.context.createGain()
  node.connect(gain)
  return gain
}

function getTimeConstant(time){
  return Math.log(time+1)/Math.log(100)
}

function getValue(start, end, fromTime, toTime, at){
  var difference = end - start
  var time = toTime - fromTime
  var truncateTime = at - fromTime
  var phase = truncateTime / time
  var value = start + phase * difference

  if (value <= start) {
      value = start
  }
  if (value >= end) {
      value = end
  }

  return value
}


/***/ }),
/* 228 */
/***/ (function(module, exports) {


module.exports = function (player) {
  /**
   * Adds a listener of an event
   * @chainable
   * @param {String} event - the event name
   * @param {Function} callback - the event handler
   * @return {SamplePlayer} the player
   * @example
   * player.on('start', function(time, note) {
   *   console.log(time, note)
   * })
   */
  player.on = function (event, cb) {
    if (arguments.length === 1 && typeof event === 'function') return player.on('event', event)
    var prop = 'on' + event
    var old = player[prop]
    player[prop] = old ? chain(old, cb) : cb
    return player
  }
  return player
}

function chain (fn1, fn2) {
  return function (a, b, c, d) { fn1(a, b, c, d); fn2(a, b, c, d) }
}


/***/ }),
/* 229 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var note = __webpack_require__(230)
var isMidi = function (n) { return n !== null && n !== [] && n >= 0 && n < 129 }
var toMidi = function (n) { return isMidi(n) ? +n : note.midi(n) }

// Adds note name to midi conversion
module.exports = function (player) {
  if (player.buffers) {
    var map = player.opts.map
    var toKey = typeof map === 'function' ? map : toMidi
    var mapper = function (name) {
      return name ? toKey(name) || name : null
    }

    player.buffers = mapBuffers(player.buffers, mapper)
    var start = player.start
    player.start = function (name, when, options) {
      var key = mapper(name)
      var dec = key % 1
      if (dec) {
        key = Math.floor(key)
        options = Object.assign(options || {}, { cents: Math.floor(dec * 100) })
      }
      return start(key, when, options)
    }
  }
  return player
}

function mapBuffers (buffers, toKey) {
  return Object.keys(buffers).reduce(function (mapped, name) {
    mapped[toKey(name)] = buffers[name]
    return mapped
  }, {})
}


/***/ }),
/* 230 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/
/**
 * A regex for matching note strings in scientific notation.
 *
 * @name regex
 * @function
 * @return {RegExp} the regexp used to parse the note name
 *
 * The note string should have the form `letter[accidentals][octave][element]`
 * where:
 *
 * - letter: (Required) is a letter from A to G either upper or lower case
 * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps).
 * They can NOT be mixed.
 * - octave: (Optional) a positive or negative integer
 * - element: (Optional) additionally anything after the duration is considered to
 * be the element name (for example: 'C2 dorian')
 *
 * The executed regex contains (by array index):
 *
 * - 0: the complete string
 * - 1: the note letter
 * - 2: the optional accidentals
 * - 3: the optional octave
 * - 4: the rest of the string (trimmed)
 *
 * @example
 * var parser = require('note-parser')
 * parser.regex.exec('c#4')
 * // => ['c#4', 'c', '#', '4', '']
 * parser.regex.exec('c#4 major')
 * // => ['c#4major', 'c', '#', '4', 'major']
 * parser.regex().exec('CMaj7')
 * // => ['CMaj7', 'C', '', '', 'Maj7']
 */
function regex () { return REGEX }

var SEMITONES = [0, 2, 4, 5, 7, 9, 11]
/**
 * Parse a note name in scientific notation an return it's components,
 * and some numeric properties including midi number and frequency.
 *
 * @name parse
 * @function
 * @param {String} note - the note string to be parsed
 * @param {Boolean} isTonic - true if the note is the tonic of something.
 * If true, en extra tonicOf property is returned. It's false by default.
 * @param {Float} tunning - The frequency of A4 note to calculate frequencies.
 * By default it 440.
 * @return {Object} the parsed note name or null if not a valid note
 *
 * The parsed note name object will ALWAYS contains:
 * - letter: the uppercase letter of the note
 * - acc: the accidentals of the note (only sharps or flats)
 * - pc: the pitch class (letter + acc)
 * - step: s a numeric representation of the letter. It's an integer from 0 to 6
 * where 0 = C, 1 = D ... 6 = B
 * - alt: a numeric representation of the accidentals. 0 means no alteration,
 * positive numbers are for sharps and negative for flats
 * - chroma: a numeric representation of the pitch class. It's like midi for
 * pitch classes. 0 = C, 1 = C#, 2 = D ... It can have negative values: -1 = Cb.
 * Can detect pitch class enhramonics.
 *
 * If the note has octave, the parser object will contain:
 * - oct: the octave number (as integer)
 * - midi: the midi number
 * - freq: the frequency (using tuning parameter as base)
 *
 * If the parameter `isTonic` is set to true, the parsed object will contain:
 * - tonicOf: the rest of the string that follows note name (left and right trimmed)
 *
 * @example
 * var parse = require('note-parser').parse
 * parse('Cb4')
 * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1,
 *         oct: 4, midi: 59, freq: 246.94165062806206 }
 * // if no octave, no midi, no freq
 * parse('fx')
 * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 })
 */
function parse (str, isTonic, tuning) {
  if (typeof str !== 'string') return null
  var m = REGEX.exec(str)
  if (!m || !isTonic && m[4]) return null

  var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }
  p.pc = p.letter + p.acc
  p.step = (p.letter.charCodeAt(0) + 3) % 7
  p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length
  p.chroma = SEMITONES[p.step] + p.alt
  if (m[3]) {
    p.oct = +m[3]
    p.midi = p.chroma + 12 * (p.oct + 1)
    p.freq = midiToFreq(p.midi, tuning)
  }
  if (isTonic) p.tonicOf = m[4]
  return p
}

/**
 * Given a midi number, return its frequency
 * @param {Integer} midi - midi note number
 * @param {Float} tuning - (Optional) the A4 tuning (440Hz by default)
 * @return {Float} frequency in hertzs
 */
function midiToFreq (midi, tuning) {
  return Math.pow(2, (midi - 69) / 12) * (tuning || 440)
}

var parser = { parse: parse, regex: regex, midiToFreq: midiToFreq }
var FNS = ['letter', 'acc', 'pc', 'step', 'alt', 'chroma', 'oct', 'midi', 'freq']
FNS.forEach(function (name) {
  parser[name] = function (src) {
    var p = parse(src)
    return p && (typeof p[name] !== 'undefined') ? p[name] : null
  }
})

module.exports = parser

// extra API docs
/**
 * Get midi of a note
 *
 * @name midi
 * @function
 * @param {String} note - the note name
 * @return {Integer} the midi number of the note or null if not a valid note
 * or the note does NOT contains octave
 * @example
 * var parser = require('note-parser')
 * parser.midi('A4') // => 69
 * parser.midi('A') // => null
 */
/**
 * Get freq of a note in hertzs (in a well tempered 440Hz A4)
 *
 * @name freq
 * @function
 * @param {String} note - the note name
 * @return {Float} the freq of the number if hertzs or null if not valid note
 * or the note does NOT contains octave
 * @example
 * var parser = require('note-parser')
 * parser.freq('A4') // => 440
 * parser.freq('A') // => null
 */


/***/ }),
/* 231 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var isArr = Array.isArray
var isObj = function (o) { return o && typeof o === 'object' }
var OPTS = {}

module.exports = function (player) {
  /**
   * Schedule a list of events to be played at specific time.
   *
   * It supports three formats of events for the events list:
   *
   * - An array with [time, note]
   * - An array with [time, object]
   * - An object with { time: ?, [name|note|midi|key]: ? }
   *
   * @param {Float} time - an absolute time to start (or AudioContext's
   * currentTime if provided number is 0)
   * @param {Array} events - the events list.
   * @return {Array} an array of ids
   *
   * @example
   * // Event format: [time, note]
   * var piano = player(ac, ...).connect(ac.destination)
   * piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ])
   *
   * @example
   * // Event format: an object { time: ?, name: ? }
   * var drums = player(ac, ...).connect(ac.destination)
   * drums.schedule(0, [
   *   { name: 'kick', time: 0 },
   *   { name: 'snare', time: 0.5 },
   *   { name: 'kick', time: 1 },
   *   { name: 'snare', time: 1.5 }
   * ])
   */
  player.schedule = function (time, events) {
    var now = player.context.currentTime
    var when = time < now ? now : time
    player.emit('schedule', when, events)
    var t, o, note, opts
    return events.map(function (event) {
      if (!event) return null
      else if (isArr(event)) {
        t = event[0]; o = event[1]
      } else {
        t = event.time; o = event
      }

      if (isObj(o)) {
        note = o.name || o.key || o.note || o.midi || null
        opts = o
      } else {
        note = o
        opts = OPTS
      }

      return player.start(note, when + (t || 0), opts)
    })
  }
  return player
}


/***/ }),
/* 232 */
/***/ (function(module, exports, __webpack_require__) {

var midimessage = __webpack_require__(233)

module.exports = function (player) {
  /**
  * Connect a player to a midi input
  *
  * The options accepts:
  *
  * - channel: the channel to listen to. Listen to all channels by default.
  *
  * @param {MIDIInput} input
  * @param {Object} options - (Optional)
  * @return {SamplePlayer} the player
  * @example
  * var piano = player(...)
  * window.navigator.requestMIDIAccess().then(function (midiAccess) {
  *   midiAccess.inputs.forEach(function (midiInput) {
  *     piano.listenToMidi(midiInput)
  *   })
  * })
  */
  player.listenToMidi = function (input, options) {
    var started = {}
    var opts = options || {}
    var gain = opts.gain || function (vel) { return vel / 127 }

    input.onmidimessage = function (msg) {
      var mm = msg.messageType ? msg : midimessage(msg)
      if (mm.messageType === 'noteon' && mm.velocity === 0) {
        mm.messageType = 'noteoff'
      }
      if (opts.channel && mm.channel !== opts.channel) return

      switch (mm.messageType) {
        case 'noteon':
          started[mm.key] = player.play(mm.key, 0, { gain: gain(mm.velocity) })
          break
        case 'noteoff':
          if (started[mm.key]) {
            started[mm.key].stop()
            delete started[mm.key]
          }
          break
      }
    }
    return player
  }
  return player
}


/***/ }),
/* 233 */
/***/ (function(module, exports, __webpack_require__) {

var require;var require;(function(e){if(true){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.midimessage=e()}})(function(){var e,t,s;return function o(e,t,s){function a(n,i){if(!t[n]){if(!e[n]){var l=typeof require=="function"&&require;if(!i&&l)return require(n,!0);if(r)return r(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[n]={exports:{}};e[n][0].call(c.exports,function(t){var s=e[n][1][t];return a(s?s:t)},c,c.exports,o,e,t,s)}return t[n].exports}var r=typeof require=="function"&&require;for(var n=0;n<s.length;n++)a(s[n]);return a}({1:[function(e,t,s){"use strict";Object.defineProperty(s,"__esModule",{value:true});s["default"]=function(e){function t(e){this._event=e;this._data=e.data;this.receivedTime=e.receivedTime;if(this._data&&this._data.length<2){console.warn("Illegal MIDI message of length",this._data.length);return}this._messageCode=e.data[0]&240;this.channel=e.data[0]&15;switch(this._messageCode){case 128:this.messageType="noteoff";this.key=e.data[1]&127;this.velocity=e.data[2]&127;break;case 144:this.messageType="noteon";this.key=e.data[1]&127;this.velocity=e.data[2]&127;break;case 160:this.messageType="keypressure";this.key=e.data[1]&127;this.pressure=e.data[2]&127;break;case 176:this.messageType="controlchange";this.controllerNumber=e.data[1]&127;this.controllerValue=e.data[2]&127;if(this.controllerNumber===120&&this.controllerValue===0){this.channelModeMessage="allsoundoff"}else if(this.controllerNumber===121){this.channelModeMessage="resetallcontrollers"}else if(this.controllerNumber===122){if(this.controllerValue===0){this.channelModeMessage="localcontroloff"}else{this.channelModeMessage="localcontrolon"}}else if(this.controllerNumber===123&&this.controllerValue===0){this.channelModeMessage="allnotesoff"}else if(this.controllerNumber===124&&this.controllerValue===0){this.channelModeMessage="omnimodeoff"}else if(this.controllerNumber===125&&this.controllerValue===0){this.channelModeMessage="omnimodeon"}else if(this.controllerNumber===126){this.channelModeMessage="monomodeon"}else if(this.controllerNumber===127){this.channelModeMessage="polymodeon"}break;case 192:this.messageType="programchange";this.program=e.data[1];break;case 208:this.messageType="channelpressure";this.pressure=e.data[1]&127;break;case 224:this.messageType="pitchbendchange";var t=e.data[2]&127;var s=e.data[1]&127;this.pitchBend=(t<<8)+s;break}}return new t(e)};t.exports=s["default"]},{}]},{},[1])(1)});
//# sourceMappingURL=dist/index.js.map

/***/ }),
/* 234 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var parser = __webpack_require__(235)

/**
 * Create a Soundfont object
 *
 * @param {AudioContext} context - the [audio context](https://developer.mozilla.org/en/docs/Web/API/AudioContext)
 * @param {Function} nameToUrl - (Optional) a function that maps the sound font name to the url
 * @return {Soundfont} a soundfont object
 */
function Soundfont (ctx, nameToUrl) {
  console.warn('new Soundfont() is deprected')
  console.log('Please use Soundfont.instrument() instead of new Soundfont().instrument()')
  if (!(this instanceof Soundfont)) return new Soundfont(ctx)

  this.nameToUrl = nameToUrl || Soundfont.nameToUrl
  this.ctx = ctx
  this.instruments = {}
  this.promises = []
}

Soundfont.prototype.onready = function (callback) {
  console.warn('deprecated API')
  console.log('Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()')
  Promise.all(this.promises).then(callback)
}

Soundfont.prototype.instrument = function (name, options) {
  console.warn('new Soundfont().instrument() is deprecated.')
  console.log('Please use Soundfont.instrument() instead.')
  var ctx = this.ctx
  name = name || 'default'
  if (name in this.instruments) return this.instruments[name]
  var inst = {name: name, play: oscillatorPlayer(ctx, options)}
  this.instruments[name] = inst
  if (name !== 'default') {
    var promise = Soundfont.instrument(ctx, name, options).then(function (instrument) {
      inst.play = instrument.play
      return inst
    })
    this.promises.push(promise)
    inst.onready = function (cb) {
      console.warn('onready is deprecated. Use Soundfont.instrument().then()')
      promise.then(cb)
    }
  } else {
    inst.onready = function (cb) {
      console.warn('onready is deprecated. Use Soundfont.instrument().then()')
      cb()
    }
  }
  return inst
}

/*
 * Load the buffers of a given instrument name. It returns a promise that resolves
 * to a hash with midi note numbers as keys, and audio buffers as values.
 *
 * @param {AudioContext} ac - the audio context
 * @param {String} name - the instrument name (it accepts an url if starts with "http")
 * @param {Object} options - (Optional) options object
 * @return {Promise} a promise that resolves to a Hash of { midiNoteNum: <AudioBuffer> }
 *
 * The options object accepts the following keys:
 *
 * - nameToUrl {Function}: a function to convert from instrument names to urls.
 * By default it uses Benjamin Gleitzman's package of
 * [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts)
 * - notes {Array}: the list of note names to be decoded (all by default)
 *
 * @example
 * var Soundfont = require('soundfont-player')
 * Soundfont.loadBuffers(ctx, 'acoustic_grand_piano').then(function(buffers) {
 *  buffers[60] // => An <AudioBuffer> corresponding to note C4
 * })
 */
function loadBuffers (ac, name, options) {
  console.warn('Soundfont.loadBuffers is deprecate.')
  console.log('Use Soundfont.instrument(..) and get buffers properties from the result.')
  return Soundfont.instrument(ac, name, options).then(function (inst) {
    return inst.buffers
  })
}
Soundfont.loadBuffers = loadBuffers

/**
 * Returns a function that plays an oscillator
 *
 * @param {AudioContext} ac - the audio context
 * @param {Hash} defaultOptions - (Optional) a hash of options:
 * - vcoType: the oscillator type (default: 'sine')
 * - gain: the output gain value (default: 0.4)
  * - destination: the player destination (default: ac.destination)
 */
function oscillatorPlayer (ctx, defaultOptions) {
  defaultOptions = defaultOptions || {}
  return function (note, time, duration, options) {
    console.warn('The oscillator player is deprecated.')
    console.log('Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.')
    var midi = note > 0 && note < 129 ? +note : parser.midi(note)
    var freq = midi ? parser.midiToFreq(midi, 440) : null
    if (!freq) return

    duration = duration || 0.2

    options = options || {}
    var destination = options.destination || defaultOptions.destination || ctx.destination
    var vcoType = options.vcoType || defaultOptions.vcoType || 'sine'
    var gain = options.gain || defaultOptions.gain || 0.4

    var vco = ctx.createOscillator()
    vco.type = vcoType
    vco.frequency.value = freq

    /* VCA */
    var vca = ctx.createGain()
    vca.gain.value = gain

    /* Connections */
    vco.connect(vca)
    vca.connect(destination)

    vco.start(time)
    if (duration > 0) vco.stop(time + duration)
    return vco
  }
}

/**
 * Given a note name, return the note midi number
 *
 * @name noteToMidi
 * @function
 * @param {String} noteName
 * @return {Integer} the note midi number or null if not a valid note name
 */
Soundfont.noteToMidi = parser.midi

module.exports = Soundfont


/***/ }),
/* 235 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (immutable) */ __webpack_exports__["regex"] = regex;
/* harmony export (immutable) */ __webpack_exports__["parse"] = parse;
/* harmony export (immutable) */ __webpack_exports__["build"] = build;
/* harmony export (immutable) */ __webpack_exports__["midi"] = midi;
/* harmony export (immutable) */ __webpack_exports__["freq"] = freq;
/* harmony export (immutable) */ __webpack_exports__["letter"] = letter;
/* harmony export (immutable) */ __webpack_exports__["acc"] = acc;
/* harmony export (immutable) */ __webpack_exports__["pc"] = pc;
/* harmony export (immutable) */ __webpack_exports__["step"] = step;
/* harmony export (immutable) */ __webpack_exports__["alt"] = alt;
/* harmony export (immutable) */ __webpack_exports__["chroma"] = chroma;
/* harmony export (immutable) */ __webpack_exports__["oct"] = oct;


// util
function fillStr (s, num) { return Array(num + 1).join(s) }
function isNum (x) { return typeof x === 'number' }
function isStr (x) { return typeof x === 'string' }
function isDef (x) { return typeof x !== 'undefined' }
function midiToFreq (midi, tuning) {
  return Math.pow(2, (midi - 69) / 12) * (tuning || 440)
}

var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/
/**
 * A regex for matching note strings in scientific notation.
 *
 * @name regex
 * @function
 * @return {RegExp} the regexp used to parse the note name
 *
 * The note string should have the form `letter[accidentals][octave][element]`
 * where:
 *
 * - letter: (Required) is a letter from A to G either upper or lower case
 * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps).
 * They can NOT be mixed.
 * - octave: (Optional) a positive or negative integer
 * - element: (Optional) additionally anything after the duration is considered to
 * be the element name (for example: 'C2 dorian')
 *
 * The executed regex contains (by array index):
 *
 * - 0: the complete string
 * - 1: the note letter
 * - 2: the optional accidentals
 * - 3: the optional octave
 * - 4: the rest of the string (trimmed)
 *
 * @example
 * var parser = require('note-parser')
 * parser.regex.exec('c#4')
 * // => ['c#4', 'c', '#', '4', '']
 * parser.regex.exec('c#4 major')
 * // => ['c#4major', 'c', '#', '4', 'major']
 * parser.regex().exec('CMaj7')
 * // => ['CMaj7', 'C', '', '', 'Maj7']
 */
function regex () { return REGEX }

var SEMITONES = [0, 2, 4, 5, 7, 9, 11]
/**
 * Parse a note name in scientific notation an return it's components,
 * and some numeric properties including midi number and frequency.
 *
 * @name parse
 * @function
 * @param {String} note - the note string to be parsed
 * @param {Boolean} isTonic - true the strings it's supposed to contain a note number
 * and some category (for example an scale: 'C# major'). It's false by default,
 * but when true, en extra tonicOf property is returned with the category ('major')
 * @param {Float} tunning - The frequency of A4 note to calculate frequencies.
 * By default it 440.
 * @return {Object} the parsed note name or null if not a valid note
 *
 * The parsed note name object will ALWAYS contains:
 * - letter: the uppercase letter of the note
 * - acc: the accidentals of the note (only sharps or flats)
 * - pc: the pitch class (letter + acc)
 * - step: s a numeric representation of the letter. It's an integer from 0 to 6
 * where 0 = C, 1 = D ... 6 = B
 * - alt: a numeric representation of the accidentals. 0 means no alteration,
 * positive numbers are for sharps and negative for flats
 * - chroma: a numeric representation of the pitch class. It's like midi for
 * pitch classes. 0 = C, 1 = C#, 2 = D ... 11 = B. Can be used to find enharmonics
 * since, for example, chroma of 'Cb' and 'B' are both 11
 *
 * If the note has octave, the parser object will contain:
 * - oct: the octave number (as integer)
 * - midi: the midi number
 * - freq: the frequency (using tuning parameter as base)
 *
 * If the parameter `isTonic` is set to true, the parsed object will contain:
 * - tonicOf: the rest of the string that follows note name (left and right trimmed)
 *
 * @example
 * var parse = require('note-parser').parse
 * parse('Cb4')
 * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1,
 *         oct: 4, midi: 59, freq: 246.94165062806206 }
 * // if no octave, no midi, no freq
 * parse('fx')
 * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 })
 */
function parse (str, isTonic, tuning) {
  if (typeof str !== 'string') return null
  var m = REGEX.exec(str)
  if (!m || (!isTonic && m[4])) return null

  var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }
  p.pc = p.letter + p.acc
  p.step = (p.letter.charCodeAt(0) + 3) % 7
  p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length
  var pos = SEMITONES[p.step] + p.alt
  p.chroma = pos < 0 ? 12 + pos : pos % 12
  if (m[3]) { // has octave
    p.oct = +m[3]
    p.midi = pos + 12 * (p.oct + 1)
    p.freq = midiToFreq(p.midi, tuning)
  }
  if (isTonic) p.tonicOf = m[4]
  return p
}

var LETTERS = 'CDEFGAB'
function accStr (n) { return !isNum(n) ? '' : n < 0 ? fillStr('b', -n) : fillStr('#', n) }
function octStr (n) { return !isNum(n) ? '' : '' + n }

/**
 * Create a string from a parsed object or `step, alteration, octave` parameters
 * @param {Object} obj - the parsed data object
 * @return {String} a note string or null if not valid parameters
 * @since 1.2
 * @example
 * parser.build(parser.parse('cb2')) // => 'Cb2'
 *
 * @example
 * // it accepts (step, alteration, octave) parameters:
 * parser.build(3) // => 'F'
 * parser.build(3, -1) // => 'Fb'
 * parser.build(3, -1, 4) // => 'Fb4'
 */
function build (s, a, o) {
  if (s === null || typeof s === 'undefined') return null
  if (s.step) return build(s.step, s.alt, s.oct)
  if (s < 0 || s > 6) return null
  return LETTERS.charAt(s) + accStr(a) + octStr(o)
}

/**
 * Get midi of a note
 *
 * @name midi
 * @function
 * @param {String|Integer} note - the note name or midi number
 * @return {Integer} the midi number of the note or null if not a valid note
 * or the note does NOT contains octave
 * @example
 * var parser = require('note-parser')
 * parser.midi('A4') // => 69
 * parser.midi('A') // => null
 * @example
 * // midi numbers are bypassed (even as strings)
 * parser.midi(60) // => 60
 * parser.midi('60') // => 60
 */
function midi (note) {
  if ((isNum(note) || isStr(note)) && note >= 0 && note < 128) return +note
  var p = parse(note)
  return p && isDef(p.midi) ? p.midi : null
}

/**
 * Get freq of a note in hertzs (in a well tempered 440Hz A4)
 *
 * @name freq
 * @function
 * @param {String} note - the note name or note midi number
 * @param {String} tuning - (Optional) the A4 frequency (440 by default)
 * @return {Float} the freq of the number if hertzs or null if not valid note
 * @example
 * var parser = require('note-parser')
 * parser.freq('A4') // => 440
 * parser.freq('A') // => null
 * @example
 * // can change tuning (440 by default)
 * parser.freq('A4', 444) // => 444
 * parser.freq('A3', 444) // => 222
 * @example
 * // it accepts midi numbers (as numbers and as strings)
 * parser.freq(69) // => 440
 * parser.freq('69', 442) // => 442
 */
function freq (note, tuning) {
  var m = midi(note)
  return m === null ? null : midiToFreq(m, tuning)
}

function letter (src) { return (parse(src) || {}).letter }
function acc (src) { return (parse(src) || {}).acc }
function pc (src) { return (parse(src) || {}).pc }
function step (src) { return (parse(src) || {}).step }
function alt (src) { return (parse(src) || {}).alt }
function chroma (src) { return (parse(src) || {}).chroma }
function oct (src) { return (parse(src) || {}).oct }


/***/ }),
/* 236 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.VolumeSlider = exports.MuteToggleButton = exports.SoundOffButton = exports.SoundOnButton = exports.TimeMarkerType = exports.TimeMarker = exports.FormattedTime = exports.ProgressBar = exports.PrevButton = exports.NextButton = exports.PauseButton = exports.PlayButton = exports.PlaybackControls = exports.Button = undefined;

var _icons = __webpack_require__(86);

Object.keys(_icons).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _icons[key];
    }
  });
});

var _Button = __webpack_require__(87);

var _Button2 = _interopRequireDefault(_Button);

var _PlaybackControls = __webpack_require__(237);

var _PlaybackControls2 = _interopRequireDefault(_PlaybackControls);

var _PlayButton = __webpack_require__(193);

var _PlayButton2 = _interopRequireDefault(_PlayButton);

var _PauseButton = __webpack_require__(194);

var _PauseButton2 = _interopRequireDefault(_PauseButton);

var _NextButton = __webpack_require__(196);

var _NextButton2 = _interopRequireDefault(_NextButton);

var _PrevButton = __webpack_require__(195);

var _PrevButton2 = _interopRequireDefault(_PrevButton);

var _ProgressBar = __webpack_require__(240);

var _ProgressBar2 = _interopRequireDefault(_ProgressBar);

var _FormattedTime = __webpack_require__(198);

var _FormattedTime2 = _interopRequireDefault(_FormattedTime);

var _TimeMarker = __webpack_require__(241);

var _TimeMarker2 = _interopRequireDefault(_TimeMarker);

var _SoundOnButton = __webpack_require__(199);

var _SoundOnButton2 = _interopRequireDefault(_SoundOnButton);

var _SoundOffButton = __webpack_require__(200);

var _SoundOffButton2 = _interopRequireDefault(_SoundOffButton);

var _MuteToggleButton = __webpack_require__(243);

var _MuteToggleButton2 = _interopRequireDefault(_MuteToggleButton);

var _VolumeSlider = __webpack_require__(244);

var _VolumeSlider2 = _interopRequireDefault(_VolumeSlider);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.Button = _Button2.default;
exports.PlaybackControls = _PlaybackControls2.default;
exports.PlayButton = _PlayButton2.default;
exports.PauseButton = _PauseButton2.default;
exports.NextButton = _NextButton2.default;
exports.PrevButton = _PrevButton2.default;
exports.ProgressBar = _ProgressBar2.default;
exports.FormattedTime = _FormattedTime2.default;
exports.TimeMarker = _TimeMarker2.default;
exports.TimeMarkerType = _TimeMarker.TimeMarkerType;
exports.SoundOnButton = _SoundOnButton2.default;
exports.SoundOffButton = _SoundOffButton2.default;
exports.MuteToggleButton = _MuteToggleButton2.default;
exports.VolumeSlider = _VolumeSlider2.default;

/***/ }),
/* 237 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _composers = __webpack_require__(88);

var _PlayButton = __webpack_require__(193);

var _PlayButton2 = _interopRequireDefault(_PlayButton);

var _PauseButton = __webpack_require__(194);

var _PauseButton2 = _interopRequireDefault(_PauseButton);

var _PrevButton = __webpack_require__(195);

var _PrevButton2 = _interopRequireDefault(_PrevButton);

var _NextButton = __webpack_require__(196);

var _NextButton2 = _interopRequireDefault(_NextButton);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

var bool = _propTypes2.default.bool,
    func = _propTypes2.default.func,
    object = _propTypes2.default.object;


var noop = function noop() {};

/**
 * Play and pause controls
 */
var PlaybackControls = (_class = function (_Component) {
  _inherits(PlaybackControls, _Component);

  function PlaybackControls() {
    _classCallCheck(this, PlaybackControls);

    return _possibleConstructorReturn(this, (PlaybackControls.__proto__ || Object.getPrototypeOf(PlaybackControls)).apply(this, arguments));
  }

  _createClass(PlaybackControls, [{
    key: 'handlePlay',
    value: function handlePlay() {
      if (this.props.isPlayable) {
        this.props.onPlaybackChange(true);
      }
    }
  }, {
    key: 'handlePause',
    value: function handlePause() {
      this.props.onPlaybackChange(false);
    }
  }, {
    key: 'render',
    value: function render() {
      var _props = this.props,
          isPlayable = _props.isPlayable,
          isPlaying = _props.isPlaying,
          showPrevious = _props.showPrevious,
          hasPrevious = _props.hasPrevious,
          onPrevious = _props.onPrevious,
          showNext = _props.showNext,
          hasNext = _props.hasNext,
          onNext = _props.onNext,
          className = _props.className,
          extraClasses = _props.extraClasses,
          childClasses = _props.childClasses,
          style = _props.style,
          childrenStyles = _props.childrenStyles;


      return _react2.default.createElement(
        'div',
        {
          className: (0, _classnames2.default)(className, { isPlayable: isPlayable, isPlaying: isPlaying }, extraClasses),
          style: style
        },
        showPrevious && _react2.default.createElement(_PrevButton2.default, {
          isEnabled: hasPrevious,
          onClick: onPrevious,
          className: childClasses.PrevButton,
          style: childrenStyles.PrevButton
        }),
        isPlaying && isPlayable ? _react2.default.createElement(_PauseButton2.default, {
          onClick: this.handlePause,
          className: childClasses.PauseButton,
          style: childrenStyles.PauseButton
        }) : _react2.default.createElement(_PlayButton2.default, {
          isEnabled: isPlayable,
          onClick: this.handlePlay,
          className: childClasses.PlayButton,
          style: childrenStyles.PlayButton
        }),
        showNext && _react2.default.createElement(_NextButton2.default, {
          isEnabled: hasNext,
          onClick: onNext,
          className: childClasses.NextButton,
          style: childrenStyles.NextButton
        })
      );
    }
  }]);

  return PlaybackControls;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'handlePlay', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handlePlay'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handlePause', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handlePause'), _class.prototype)), _class);
PlaybackControls.propTypes = {
  onPlaybackChange: func.isRequired,
  isPlayable: bool,
  isPlaying: bool,
  showPrevious: bool,
  hasPrevious: bool,
  onPrevious: func,
  showNext: bool,
  hasNext: bool,
  onNext: func,
  style: object
};
PlaybackControls.defaultProps = {
  isPlayable: false,
  isPlaying: false,
  showPrevious: true,
  hasPrevious: false,
  onPrevious: noop,
  showNext: true,
  hasNext: false,
  onNext: noop,
  style: {}
};
exports.default = (0, _composers.compose)((0, _composers.withChildrenStyles)(), (0, _composers.withCustomizableClasses)('PlaybackControls'), (0, _composers.withChildClasses)())(PlaybackControls);

/***/ }),
/* 238 */
/***/ (function(module, exports, __webpack_require__) {

/* 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 the internal argument placeholder. */
var PLACEHOLDER = '__lodash_placeholder__';

/** Used to compose bitmasks for function metadata. */
var BIND_FLAG = 1,
    BIND_KEY_FLAG = 2,
    CURRY_BOUND_FLAG = 4,
    CURRY_FLAG = 8,
    CURRY_RIGHT_FLAG = 16,
    PARTIAL_FLAG = 32,
    PARTIAL_RIGHT_FLAG = 64,
    ARY_FLAG = 128,
    REARG_FLAG = 256,
    FLIP_FLAG = 512;

/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0,
    MAX_SAFE_INTEGER = 9007199254740991,
    MAX_INTEGER = 1.7976931348623157e+308,
    NAN = 0 / 0;

/** Used to associate wrap methods with their bit flags. */
var wrapFlags = [
  ['ary', ARY_FLAG],
  ['bind', BIND_FLAG],
  ['bindKey', BIND_KEY_FLAG],
  ['curry', CURRY_FLAG],
  ['curryRight', CURRY_RIGHT_FLAG],
  ['flip', FLIP_FLAG],
  ['partial', PARTIAL_FLAG],
  ['partialRight', PARTIAL_RIGHT_FLAG],
  ['rearg', REARG_FLAG]
];

/** `Object#toString` result references. */
var funcTag = '[object Function]',
    genTag = '[object GeneratorFunction]',
    symbolTag = '[object Symbol]';

/**
 * Used to match `RegExp`
 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
 */
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;

/** Used to match leading and trailing whitespace. */
var reTrim = /^\s+|\s+$/g;

/** Used to match wrap detail comments. */
var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
    reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
    reSplitDetails = /,? & /;

/** 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 host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;

/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;

/** Used to detect unsigned integer values. */
var reIsUint = /^(?:0|[1-9]\d*)$/;

/** 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')();

/**
 * A faster alternative to `Function#apply`, this function invokes `func`
 * with the `this` binding of `thisArg` and the arguments of `args`.
 *
 * @private
 * @param {Function} func The function to invoke.
 * @param {*} thisArg The `this` binding of `func`.
 * @param {Array} args The arguments to invoke `func` with.
 * @returns {*} Returns the result of `func`.
 */
function apply(func, thisArg, args) {
  switch (args.length) {
    case 0: return func.call(thisArg);
    case 1: return func.call(thisArg, args[0]);
    case 2: return func.call(thisArg, args[0], args[1]);
    case 3: return func.call(thisArg, args[0], args[1], args[2]);
  }
  return func.apply(thisArg, args);
}

/**
 * A specialized version of `_.forEach` for arrays without support for
 * iteratee shorthands.
 *
 * @private
 * @param {Array} [array] The array to iterate over.
 * @param {Function} iteratee The function invoked per iteration.
 * @returns {Array} Returns `array`.
 */
function arrayEach(array, iteratee) {
  var index = -1,
      length = array ? array.length : 0;

  while (++index < length) {
    if (iteratee(array[index], index, array) === false) {
      break;
    }
  }
  return array;
}

/**
 * A specialized version of `_.includes` for arrays without support for
 * specifying an index to search from.
 *
 * @private
 * @param {Array} [array] The array to inspect.
 * @param {*} target The value to search for.
 * @returns {boolean} Returns `true` if `target` is found, else `false`.
 */
function arrayIncludes(array, value) {
  var length = array ? array.length : 0;
  return !!length && baseIndexOf(array, value, 0) > -1;
}

/**
 * The base implementation of `_.findIndex` and `_.findLastIndex` without
 * support for iteratee shorthands.
 *
 * @private
 * @param {Array} array The array to inspect.
 * @param {Function} predicate The function invoked per iteration.
 * @param {number} fromIndex The index to search from.
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function baseFindIndex(array, predicate, fromIndex, fromRight) {
  var length = array.length,
      index = fromIndex + (fromRight ? 1 : -1);

  while ((fromRight ? index-- : ++index < length)) {
    if (predicate(array[index], index, array)) {
      return index;
    }
  }
  return -1;
}

/**
 * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
 *
 * @private
 * @param {Array} array The array to inspect.
 * @param {*} value The value to search for.
 * @param {number} fromIndex The index to search from.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function baseIndexOf(array, value, fromIndex) {
  if (value !== value) {
    return baseFindIndex(array, baseIsNaN, fromIndex);
  }
  var index = fromIndex - 1,
      length = array.length;

  while (++index < length) {
    if (array[index] === value) {
      return index;
    }
  }
  return -1;
}

/**
 * The base implementation of `_.isNaN` without support for number objects.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
 */
function baseIsNaN(value) {
  return value !== value;
}

/**
 * Gets the number of `placeholder` occurrences in `array`.
 *
 * @private
 * @param {Array} array The array to inspect.
 * @param {*} placeholder The placeholder to search for.
 * @returns {number} Returns the placeholder count.
 */
function countHolders(array, placeholder) {
  var length = array.length,
      result = 0;

  while (length--) {
    if (array[length] === placeholder) {
      result++;
    }
  }
  return result;
}

/**
 * Gets the value at `key` of `object`.
 *
 * @private
 * @param {Object} [object] The object to query.
 * @param {string} key The key of the property to get.
 * @returns {*} Returns the property value.
 */
function getValue(object, key) {
  return object == null ? undefined : object[key];
}

/**
 * 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;
}

/**
 * Replaces all `placeholder` elements in `array` with an internal placeholder
 * and returns an array of their indexes.
 *
 * @private
 * @param {Array} array The array to modify.
 * @param {*} placeholder The placeholder to replace.
 * @returns {Array} Returns the new array of placeholder indexes.
 */
function replaceHolders(array, placeholder) {
  var index = -1,
      length = array.length,
      resIndex = 0,
      result = [];

  while (++index < length) {
    var value = array[index];
    if (value === placeholder || value === PLACEHOLDER) {
      array[index] = PLACEHOLDER;
      result[resIndex++] = index;
    }
  }
  return result;
}

/** Used for built-in method references. */
var funcProto = Function.prototype,
    objectProto = Object.prototype;

/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];

/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
  return uid ? ('Symbol(src)_1.' + uid) : '';
}());

/** 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 resolve the
 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
 * of values.
 */
var objectToString = objectProto.toString;

/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);

/** Built-in value references. */
var objectCreate = Object.create;

/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max,
    nativeMin = Math.min;

/* Used to set `toString` methods. */
var defineProperty = (function() {
  var func = getNative(Object, 'defineProperty'),
      name = getNative.name;

  return (name && name.length > 2) ? func : undefined;
}());

/**
 * The base implementation of `_.create` without support for assigning
 * properties to the created object.
 *
 * @private
 * @param {Object} prototype The object to inherit from.
 * @returns {Object} Returns the new object.
 */
function baseCreate(proto) {
  return isObject(proto) ? objectCreate(proto) : {};
}

/**
 * The base implementation of `_.isNative` without bad shim checks.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a native function,
 *  else `false`.
 */
function baseIsNative(value) {
  if (!isObject(value) || isMasked(value)) {
    return false;
  }
  var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
  return pattern.test(toSource(value));
}

/**
 * Creates an array that is the composition of partially applied arguments,
 * placeholders, and provided arguments into a single array of arguments.
 *
 * @private
 * @param {Array} args The provided arguments.
 * @param {Array} partials The arguments to prepend to those provided.
 * @param {Array} holders The `partials` placeholder indexes.
 * @params {boolean} [isCurried] Specify composing for a curried function.
 * @returns {Array} Returns the new array of composed arguments.
 */
function composeArgs(args, partials, holders, isCurried) {
  var argsIndex = -1,
      argsLength = args.length,
      holdersLength = holders.length,
      leftIndex = -1,
      leftLength = partials.length,
      rangeLength = nativeMax(argsLength - holdersLength, 0),
      result = Array(leftLength + rangeLength),
      isUncurried = !isCurried;

  while (++leftIndex < leftLength) {
    result[leftIndex] = partials[leftIndex];
  }
  while (++argsIndex < holdersLength) {
    if (isUncurried || argsIndex < argsLength) {
      result[holders[argsIndex]] = args[argsIndex];
    }
  }
  while (rangeLength--) {
    result[leftIndex++] = args[argsIndex++];
  }
  return result;
}

/**
 * This function is like `composeArgs` except that the arguments composition
 * is tailored for `_.partialRight`.
 *
 * @private
 * @param {Array} args The provided arguments.
 * @param {Array} partials The arguments to append to those provided.
 * @param {Array} holders The `partials` placeholder indexes.
 * @params {boolean} [isCurried] Specify composing for a curried function.
 * @returns {Array} Returns the new array of composed arguments.
 */
function composeArgsRight(args, partials, holders, isCurried) {
  var argsIndex = -1,
      argsLength = args.length,
      holdersIndex = -1,
      holdersLength = holders.length,
      rightIndex = -1,
      rightLength = partials.length,
      rangeLength = nativeMax(argsLength - holdersLength, 0),
      result = Array(rangeLength + rightLength),
      isUncurried = !isCurried;

  while (++argsIndex < rangeLength) {
    result[argsIndex] = args[argsIndex];
  }
  var offset = argsIndex;
  while (++rightIndex < rightLength) {
    result[offset + rightIndex] = partials[rightIndex];
  }
  while (++holdersIndex < holdersLength) {
    if (isUncurried || argsIndex < argsLength) {
      result[offset + holders[holdersIndex]] = args[argsIndex++];
    }
  }
  return result;
}

/**
 * Copies the values of `source` to `array`.
 *
 * @private
 * @param {Array} source The array to copy values from.
 * @param {Array} [array=[]] The array to copy values to.
 * @returns {Array} Returns `array`.
 */
function copyArray(source, array) {
  var index = -1,
      length = source.length;

  array || (array = Array(length));
  while (++index < length) {
    array[index] = source[index];
  }
  return array;
}

/**
 * Creates a function that wraps `func` to invoke it with the optional `this`
 * binding of `thisArg`.
 *
 * @private
 * @param {Function} func The function to wrap.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @param {*} [thisArg] The `this` binding of `func`.
 * @returns {Function} Returns the new wrapped function.
 */
function createBind(func, bitmask, thisArg) {
  var isBind = bitmask & BIND_FLAG,
      Ctor = createCtor(func);

  function wrapper() {
    var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
    return fn.apply(isBind ? thisArg : this, arguments);
  }
  return wrapper;
}

/**
 * Creates a function that produces an instance of `Ctor` regardless of
 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
 *
 * @private
 * @param {Function} Ctor The constructor to wrap.
 * @returns {Function} Returns the new wrapped function.
 */
function createCtor(Ctor) {
  return function() {
    // Use a `switch` statement to work with class constructors. See
    // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
    // for more details.
    var args = arguments;
    switch (args.length) {
      case 0: return new Ctor;
      case 1: return new Ctor(args[0]);
      case 2: return new Ctor(args[0], args[1]);
      case 3: return new Ctor(args[0], args[1], args[2]);
      case 4: return new Ctor(args[0], args[1], args[2], args[3]);
      case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
      case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
      case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
    }
    var thisBinding = baseCreate(Ctor.prototype),
        result = Ctor.apply(thisBinding, args);

    // Mimic the constructor's `return` behavior.
    // See https://es5.github.io/#x13.2.2 for more details.
    return isObject(result) ? result : thisBinding;
  };
}

/**
 * Creates a function that wraps `func` to enable currying.
 *
 * @private
 * @param {Function} func The function to wrap.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @param {number} arity The arity of `func`.
 * @returns {Function} Returns the new wrapped function.
 */
function createCurry(func, bitmask, arity) {
  var Ctor = createCtor(func);

  function wrapper() {
    var length = arguments.length,
        args = Array(length),
        index = length,
        placeholder = getHolder(wrapper);

    while (index--) {
      args[index] = arguments[index];
    }
    var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
      ? []
      : replaceHolders(args, placeholder);

    length -= holders.length;
    if (length < arity) {
      return createRecurry(
        func, bitmask, createHybrid, wrapper.placeholder, undefined,
        args, holders, undefined, undefined, arity - length);
    }
    var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
    return apply(fn, this, args);
  }
  return wrapper;
}

/**
 * Creates a function that wraps `func` to invoke it with optional `this`
 * binding of `thisArg`, partial application, and currying.
 *
 * @private
 * @param {Function|string} func The function or method name to wrap.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @param {*} [thisArg] The `this` binding of `func`.
 * @param {Array} [partials] The arguments to prepend to those provided to
 *  the new function.
 * @param {Array} [holders] The `partials` placeholder indexes.
 * @param {Array} [partialsRight] The arguments to append to those provided
 *  to the new function.
 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
 * @param {Array} [argPos] The argument positions of the new function.
 * @param {number} [ary] The arity cap of `func`.
 * @param {number} [arity] The arity of `func`.
 * @returns {Function} Returns the new wrapped function.
 */
function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
  var isAry = bitmask & ARY_FLAG,
      isBind = bitmask & BIND_FLAG,
      isBindKey = bitmask & BIND_KEY_FLAG,
      isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG),
      isFlip = bitmask & FLIP_FLAG,
      Ctor = isBindKey ? undefined : createCtor(func);

  function wrapper() {
    var length = arguments.length,
        args = Array(length),
        index = length;

    while (index--) {
      args[index] = arguments[index];
    }
    if (isCurried) {
      var placeholder = getHolder(wrapper),
          holdersCount = countHolders(args, placeholder);
    }
    if (partials) {
      args = composeArgs(args, partials, holders, isCurried);
    }
    if (partialsRight) {
      args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
    }
    length -= holdersCount;
    if (isCurried && length < arity) {
      var newHolders = replaceHolders(args, placeholder);
      return createRecurry(
        func, bitmask, createHybrid, wrapper.placeholder, thisArg,
        args, newHolders, argPos, ary, arity - length
      );
    }
    var thisBinding = isBind ? thisArg : this,
        fn = isBindKey ? thisBinding[func] : func;

    length = args.length;
    if (argPos) {
      args = reorder(args, argPos);
    } else if (isFlip && length > 1) {
      args.reverse();
    }
    if (isAry && ary < length) {
      args.length = ary;
    }
    if (this && this !== root && this instanceof wrapper) {
      fn = Ctor || createCtor(fn);
    }
    return fn.apply(thisBinding, args);
  }
  return wrapper;
}

/**
 * Creates a function that wraps `func` to invoke it with the `this` binding
 * of `thisArg` and `partials` prepended to the arguments it receives.
 *
 * @private
 * @param {Function} func The function to wrap.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @param {*} thisArg The `this` binding of `func`.
 * @param {Array} partials The arguments to prepend to those provided to
 *  the new function.
 * @returns {Function} Returns the new wrapped function.
 */
function createPartial(func, bitmask, thisArg, partials) {
  var isBind = bitmask & BIND_FLAG,
      Ctor = createCtor(func);

  function wrapper() {
    var argsIndex = -1,
        argsLength = arguments.length,
        leftIndex = -1,
        leftLength = partials.length,
        args = Array(leftLength + argsLength),
        fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;

    while (++leftIndex < leftLength) {
      args[leftIndex] = partials[leftIndex];
    }
    while (argsLength--) {
      args[leftIndex++] = arguments[++argsIndex];
    }
    return apply(fn, isBind ? thisArg : this, args);
  }
  return wrapper;
}

/**
 * Creates a function that wraps `func` to continue currying.
 *
 * @private
 * @param {Function} func The function to wrap.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @param {Function} wrapFunc The function to create the `func` wrapper.
 * @param {*} placeholder The placeholder value.
 * @param {*} [thisArg] The `this` binding of `func`.
 * @param {Array} [partials] The arguments to prepend to those provided to
 *  the new function.
 * @param {Array} [holders] The `partials` placeholder indexes.
 * @param {Array} [argPos] The argument positions of the new function.
 * @param {number} [ary] The arity cap of `func`.
 * @param {number} [arity] The arity of `func`.
 * @returns {Function} Returns the new wrapped function.
 */
function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
  var isCurry = bitmask & CURRY_FLAG,
      newHolders = isCurry ? holders : undefined,
      newHoldersRight = isCurry ? undefined : holders,
      newPartials = isCurry ? partials : undefined,
      newPartialsRight = isCurry ? undefined : partials;

  bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
  bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);

  if (!(bitmask & CURRY_BOUND_FLAG)) {
    bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
  }

  var result = wrapFunc(func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, newHoldersRight, argPos, ary, arity);
  result.placeholder = placeholder;
  return setWrapToString(result, func, bitmask);
}

/**
 * Creates a function that either curries or invokes `func` with optional
 * `this` binding and partially applied arguments.
 *
 * @private
 * @param {Function|string} func The function or method name to wrap.
 * @param {number} bitmask The bitmask flags.
 *  The bitmask may be composed of the following flags:
 *     1 - `_.bind`
 *     2 - `_.bindKey`
 *     4 - `_.curry` or `_.curryRight` of a bound function
 *     8 - `_.curry`
 *    16 - `_.curryRight`
 *    32 - `_.partial`
 *    64 - `_.partialRight`
 *   128 - `_.rearg`
 *   256 - `_.ary`
 *   512 - `_.flip`
 * @param {*} [thisArg] The `this` binding of `func`.
 * @param {Array} [partials] The arguments to be partially applied.
 * @param {Array} [holders] The `partials` placeholder indexes.
 * @param {Array} [argPos] The argument positions of the new function.
 * @param {number} [ary] The arity cap of `func`.
 * @param {number} [arity] The arity of `func`.
 * @returns {Function} Returns the new wrapped function.
 */
function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
  var isBindKey = bitmask & BIND_KEY_FLAG;
  if (!isBindKey && typeof func != 'function') {
    throw new TypeError(FUNC_ERROR_TEXT);
  }
  var length = partials ? partials.length : 0;
  if (!length) {
    bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
    partials = holders = undefined;
  }
  ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
  arity = arity === undefined ? arity : toInteger(arity);
  length -= holders ? holders.length : 0;

  if (bitmask & PARTIAL_RIGHT_FLAG) {
    var partialsRight = partials,
        holdersRight = holders;

    partials = holders = undefined;
  }

  var newData = [
    func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
    argPos, ary, arity
  ];

  func = newData[0];
  bitmask = newData[1];
  thisArg = newData[2];
  partials = newData[3];
  holders = newData[4];
  arity = newData[9] = newData[9] == null
    ? (isBindKey ? 0 : func.length)
    : nativeMax(newData[9] - length, 0);

  if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) {
    bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG);
  }
  if (!bitmask || bitmask == BIND_FLAG) {
    var result = createBind(func, bitmask, thisArg);
  } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) {
    result = createCurry(func, bitmask, arity);
  } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) {
    result = createPartial(func, bitmask, thisArg, partials);
  } else {
    result = createHybrid.apply(undefined, newData);
  }
  return setWrapToString(result, func, bitmask);
}

/**
 * Gets the argument placeholder value for `func`.
 *
 * @private
 * @param {Function} func The function to inspect.
 * @returns {*} Returns the placeholder value.
 */
function getHolder(func) {
  var object = func;
  return object.placeholder;
}

/**
 * Gets the native function at `key` of `object`.
 *
 * @private
 * @param {Object} object The object to query.
 * @param {string} key The key of the method to get.
 * @returns {*} Returns the function if it's native, else `undefined`.
 */
function getNative(object, key) {
  var value = getValue(object, key);
  return baseIsNative(value) ? value : undefined;
}

/**
 * Extracts wrapper details from the `source` body comment.
 *
 * @private
 * @param {string} source The source to inspect.
 * @returns {Array} Returns the wrapper details.
 */
function getWrapDetails(source) {
  var match = source.match(reWrapDetails);
  return match ? match[1].split(reSplitDetails) : [];
}

/**
 * Inserts wrapper `details` in a comment at the top of the `source` body.
 *
 * @private
 * @param {string} source The source to modify.
 * @returns {Array} details The details to insert.
 * @returns {string} Returns the modified source.
 */
function insertWrapDetails(source, details) {
  var length = details.length,
      lastIndex = length - 1;

  details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
  details = details.join(length > 2 ? ', ' : ' ');
  return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
}

/**
 * Checks if `value` is a valid array-like index.
 *
 * @private
 * @param {*} value The value to check.
 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
 */
function isIndex(value, length) {
  length = length == null ? MAX_SAFE_INTEGER : length;
  return !!length &&
    (typeof value == 'number' || reIsUint.test(value)) &&
    (value > -1 && value % 1 == 0 && value < length);
}

/**
 * Checks if `func` has its source masked.
 *
 * @private
 * @param {Function} func The function to check.
 * @returns {boolean} Returns `true` if `func` is masked, else `false`.
 */
function isMasked(func) {
  return !!maskSrcKey && (maskSrcKey in func);
}

/**
 * Reorder `array` according to the specified indexes where the element at
 * the first index is assigned as the first element, the element at
 * the second index is assigned as the second element, and so on.
 *
 * @private
 * @param {Array} array The array to reorder.
 * @param {Array} indexes The arranged array indexes.
 * @returns {Array} Returns `array`.
 */
function reorder(array, indexes) {
  var arrLength = array.length,
      length = nativeMin(indexes.length, arrLength),
      oldArray = copyArray(array);

  while (length--) {
    var index = indexes[length];
    array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
  }
  return array;
}

/**
 * Sets the `toString` method of `wrapper` to mimic the source of `reference`
 * with wrapper details in a comment at the top of the source body.
 *
 * @private
 * @param {Function} wrapper The function to modify.
 * @param {Function} reference The reference function.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @returns {Function} Returns `wrapper`.
 */
var setWrapToString = !defineProperty ? identity : function(wrapper, reference, bitmask) {
  var source = (reference + '');
  return defineProperty(wrapper, 'toString', {
    'configurable': true,
    'enumerable': false,
    'value': constant(insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)))
  });
};

/**
 * Converts `func` to its source code.
 *
 * @private
 * @param {Function} func The function to process.
 * @returns {string} Returns the source code.
 */
function toSource(func) {
  if (func != null) {
    try {
      return funcToString.call(func);
    } catch (e) {}
    try {
      return (func + '');
    } catch (e) {}
  }
  return '';
}

/**
 * Updates wrapper `details` based on `bitmask` flags.
 *
 * @private
 * @returns {Array} details The details to modify.
 * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
 * @returns {Array} Returns `details`.
 */
function updateWrapDetails(details, bitmask) {
  arrayEach(wrapFlags, function(pair) {
    var value = '_.' + pair[0];
    if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
      details.push(value);
    }
  });
  return details.sort();
}

/**
 * Creates a function that accepts arguments of `func` and either invokes
 * `func` returning its result, if at least `arity` number of arguments have
 * been provided, or returns a function that accepts the remaining `func`
 * arguments, and so on. The arity of `func` may be specified if `func.length`
 * is not sufficient.
 *
 * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
 * may be used as a placeholder for provided arguments.
 *
 * **Note:** This method doesn't set the "length" property of curried functions.
 *
 * @static
 * @memberOf _
 * @since 2.0.0
 * @category Function
 * @param {Function} func The function to curry.
 * @param {number} [arity=func.length] The arity of `func`.
 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
 * @returns {Function} Returns the new curried function.
 * @example
 *
 * var abc = function(a, b, c) {
 *   return [a, b, c];
 * };
 *
 * var curried = _.curry(abc);
 *
 * curried(1)(2)(3);
 * // => [1, 2, 3]
 *
 * curried(1, 2)(3);
 * // => [1, 2, 3]
 *
 * curried(1, 2, 3);
 * // => [1, 2, 3]
 *
 * // Curried with placeholders.
 * curried(1)(_, 3)(2);
 * // => [1, 2, 3]
 */
function curry(func, arity, guard) {
  arity = guard ? undefined : arity;
  var result = createWrap(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
  result.placeholder = curry.placeholder;
  return result;
}

/**
 * Checks if `value` is classified as a `Function` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a function, else `false`.
 * @example
 *
 * _.isFunction(_);
 * // => true
 *
 * _.isFunction(/abc/);
 * // => false
 */
function isFunction(value) {
  // The use of `Object#toString` avoids issues with the `typeof` operator
  // in Safari 8-9 which returns 'object' for typed array and other constructors.
  var tag = isObject(value) ? objectToString.call(value) : '';
  return tag == funcTag || tag == genTag;
}

/**
 * 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 finite number.
 *
 * @static
 * @memberOf _
 * @since 4.12.0
 * @category Lang
 * @param {*} value The value to convert.
 * @returns {number} Returns the converted number.
 * @example
 *
 * _.toFinite(3.2);
 * // => 3.2
 *
 * _.toFinite(Number.MIN_VALUE);
 * // => 5e-324
 *
 * _.toFinite(Infinity);
 * // => 1.7976931348623157e+308
 *
 * _.toFinite('3.2');
 * // => 3.2
 */
function toFinite(value) {
  if (!value) {
    return value === 0 ? value : 0;
  }
  value = toNumber(value);
  if (value === INFINITY || value === -INFINITY) {
    var sign = (value < 0 ? -1 : 1);
    return sign * MAX_INTEGER;
  }
  return value === value ? value : 0;
}

/**
 * Converts `value` to an integer.
 *
 * **Note:** This method is loosely based on
 * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to convert.
 * @returns {number} Returns the converted integer.
 * @example
 *
 * _.toInteger(3.2);
 * // => 3
 *
 * _.toInteger(Number.MIN_VALUE);
 * // => 0
 *
 * _.toInteger(Infinity);
 * // => 1.7976931348623157e+308
 *
 * _.toInteger('3.2');
 * // => 3
 */
function toInteger(value) {
  var result = toFinite(value),
      remainder = result % 1;

  return result === result ? (remainder ? result - remainder : result) : 0;
}

/**
 * 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);
}

/**
 * Creates a function that returns `value`.
 *
 * @static
 * @memberOf _
 * @since 2.4.0
 * @category Util
 * @param {*} value The value to return from the new function.
 * @returns {Function} Returns the new constant function.
 * @example
 *
 * var objects = _.times(2, _.constant({ 'a': 1 }));
 *
 * console.log(objects);
 * // => [{ 'a': 1 }, { 'a': 1 }]
 *
 * console.log(objects[0] === objects[1]);
 * // => true
 */
function constant(value) {
  return function() {
    return value;
  };
}

/**
 * This method returns the first argument it receives.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Util
 * @param {*} value Any value.
 * @returns {*} Returns `value`.
 * @example
 *
 * var object = { 'a': 1 };
 *
 * console.log(_.identity(object) === object);
 * // => true
 */
function identity(value) {
  return value;
}

// Assign default placeholders.
curry.placeholder = {};

module.exports = curry;

/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(190)))

/***/ }),
/* 239 */
/***/ (function(module, exports, __webpack_require__) {

/* 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 MAX_SAFE_INTEGER = 9007199254740991;

/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
    funcTag = '[object Function]',
    genTag = '[object GeneratorFunction]';

/** 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')();

/**
 * A faster alternative to `Function#apply`, this function invokes `func`
 * with the `this` binding of `thisArg` and the arguments of `args`.
 *
 * @private
 * @param {Function} func The function to invoke.
 * @param {*} thisArg The `this` binding of `func`.
 * @param {Array} args The arguments to invoke `func` with.
 * @returns {*} Returns the result of `func`.
 */
function apply(func, thisArg, args) {
  switch (args.length) {
    case 0: return func.call(thisArg);
    case 1: return func.call(thisArg, args[0]);
    case 2: return func.call(thisArg, args[0], args[1]);
    case 3: return func.call(thisArg, args[0], args[1], args[2]);
  }
  return func.apply(thisArg, args);
}

/**
 * Appends the elements of `values` to `array`.
 *
 * @private
 * @param {Array} array The array to modify.
 * @param {Array} values The values to append.
 * @returns {Array} Returns `array`.
 */
function arrayPush(array, values) {
  var index = -1,
      length = values.length,
      offset = array.length;

  while (++index < length) {
    array[offset + index] = values[index];
  }
  return array;
}

/** Used for built-in method references. */
var objectProto = Object.prototype;

/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;

/**
 * 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 Symbol = root.Symbol,
    propertyIsEnumerable = objectProto.propertyIsEnumerable,
    spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined;

/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max;

/**
 * The base implementation of `_.flatten` with support for restricting flattening.
 *
 * @private
 * @param {Array} array The array to flatten.
 * @param {number} depth The maximum recursion depth.
 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
 * @param {Array} [result=[]] The initial result value.
 * @returns {Array} Returns the new flattened array.
 */
function baseFlatten(array, depth, predicate, isStrict, result) {
  var index = -1,
      length = array.length;

  predicate || (predicate = isFlattenable);
  result || (result = []);

  while (++index < length) {
    var value = array[index];
    if (depth > 0 && predicate(value)) {
      if (depth > 1) {
        // Recursively flatten arrays (susceptible to call stack limits).
        baseFlatten(value, depth - 1, predicate, isStrict, result);
      } else {
        arrayPush(result, value);
      }
    } else if (!isStrict) {
      result[result.length] = value;
    }
  }
  return result;
}

/**
 * The base implementation of `_.rest` which doesn't validate or coerce arguments.
 *
 * @private
 * @param {Function} func The function to apply a rest parameter to.
 * @param {number} [start=func.length-1] The start position of the rest parameter.
 * @returns {Function} Returns the new function.
 */
function baseRest(func, start) {
  start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
  return function() {
    var args = arguments,
        index = -1,
        length = nativeMax(args.length - start, 0),
        array = Array(length);

    while (++index < length) {
      array[index] = args[start + index];
    }
    index = -1;
    var otherArgs = Array(start + 1);
    while (++index < start) {
      otherArgs[index] = args[index];
    }
    otherArgs[start] = array;
    return apply(func, this, otherArgs);
  };
}

/**
 * Creates a `_.flow` or `_.flowRight` function.
 *
 * @private
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {Function} Returns the new flow function.
 */
function createFlow(fromRight) {
  return baseRest(function(funcs) {
    funcs = baseFlatten(funcs, 1);

    var length = funcs.length,
        index = length;

    if (fromRight) {
      funcs.reverse();
    }
    while (index--) {
      if (typeof funcs[index] != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
    }
    return function() {
      var index = 0,
          result = length ? funcs[index].apply(this, arguments) : arguments[0];

      while (++index < length) {
        result = funcs[index].call(this, result);
      }
      return result;
    };
  });
}

/**
 * Checks if `value` is a flattenable `arguments` object or array.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
 */
function isFlattenable(value) {
  return isArray(value) || isArguments(value) ||
    !!(spreadableSymbol && value && value[spreadableSymbol]);
}

/**
 * Checks if `value` is likely an `arguments` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an `arguments` object,
 *  else `false`.
 * @example
 *
 * _.isArguments(function() { return arguments; }());
 * // => true
 *
 * _.isArguments([1, 2, 3]);
 * // => false
 */
function isArguments(value) {
  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
}

/**
 * Checks if `value` is classified as an `Array` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an array, else `false`.
 * @example
 *
 * _.isArray([1, 2, 3]);
 * // => true
 *
 * _.isArray(document.body.children);
 * // => false
 *
 * _.isArray('abc');
 * // => false
 *
 * _.isArray(_.noop);
 * // => false
 */
var isArray = Array.isArray;

/**
 * Checks if `value` is array-like. A value is considered array-like if it's
 * not a function and has a `value.length` that's an integer greater than or
 * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
 * @example
 *
 * _.isArrayLike([1, 2, 3]);
 * // => true
 *
 * _.isArrayLike(document.body.children);
 * // => true
 *
 * _.isArrayLike('abc');
 * // => true
 *
 * _.isArrayLike(_.noop);
 * // => false
 */
function isArrayLike(value) {
  return value != null && isLength(value.length) && !isFunction(value);
}

/**
 * This method is like `_.isArrayLike` except that it also checks if `value`
 * is an object.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an array-like object,
 *  else `false`.
 * @example
 *
 * _.isArrayLikeObject([1, 2, 3]);
 * // => true
 *
 * _.isArrayLikeObject(document.body.children);
 * // => true
 *
 * _.isArrayLikeObject('abc');
 * // => false
 *
 * _.isArrayLikeObject(_.noop);
 * // => false
 */
function isArrayLikeObject(value) {
  return isObjectLike(value) && isArrayLike(value);
}

/**
 * Checks if `value` is classified as a `Function` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a function, else `false`.
 * @example
 *
 * _.isFunction(_);
 * // => true
 *
 * _.isFunction(/abc/);
 * // => false
 */
function isFunction(value) {
  // The use of `Object#toString` avoids issues with the `typeof` operator
  // in Safari 8-9 which returns 'object' for typed array and other constructors.
  var tag = isObject(value) ? objectToString.call(value) : '';
  return tag == funcTag || tag == genTag;
}

/**
 * Checks if `value` is a valid array-like length.
 *
 * **Note:** This method is loosely based on
 * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
 * @example
 *
 * _.isLength(3);
 * // => true
 *
 * _.isLength(Number.MIN_VALUE);
 * // => false
 *
 * _.isLength(Infinity);
 * // => false
 *
 * _.isLength('3');
 * // => false
 */
function isLength(value) {
  return typeof value == 'number' &&
    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}

/**
 * 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';
}

/**
 * This method is like `_.flow` except that it creates a function that
 * invokes the given functions from right to left.
 *
 * @static
 * @since 3.0.0
 * @memberOf _
 * @category Util
 * @param {...(Function|Function[])} [funcs] The functions to invoke.
 * @returns {Function} Returns the new composite function.
 * @see _.flow
 * @example
 *
 * function square(n) {
 *   return n * n;
 * }
 *
 * var addSquare = _.flowRight([square, _.add]);
 * addSquare(1, 2);
 * // => 9
 */
var flowRight = createFlow(true);

module.exports = flowRight;

/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(190)))

/***/ }),
/* 240 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _composers = __webpack_require__(88);

var _RangeControlOverlay = __webpack_require__(197);

var _RangeControlOverlay2 = _interopRequireDefault(_RangeControlOverlay);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

var number = _propTypes2.default.number,
    bool = _propTypes2.default.bool,
    func = _propTypes2.default.func,
    object = _propTypes2.default.object;

/**
 * Seekable progress bar
 *
 * TODO: Make use of the range input element?
 */

var ProgressBar = (_class = function (_Component) {
  _inherits(ProgressBar, _Component);

  function ProgressBar(props) {
    _classCallCheck(this, ProgressBar);

    var _this = _possibleConstructorReturn(this, (ProgressBar.__proto__ || Object.getPrototypeOf(ProgressBar)).call(this, props));

    _this.progressBarEl = null;

    _this.state = {
      currentIntent: 0
    };
    return _this;
  }

  _createClass(ProgressBar, [{
    key: 'storeRef',
    value: function storeRef(rootEl) {
      this.progressBarEl = rootEl;
    }
  }, {
    key: 'handleSeek',
    value: function handleSeek(relativeTime) {
      var _props = this.props,
          isSeekable = _props.isSeekable,
          onSeek = _props.onSeek,
          totalTime = _props.totalTime;


      if (isSeekable) {
        onSeek(relativeTime * totalTime);
      }
    }
  }, {
    key: 'handleSeekStart',
    value: function handleSeekStart(relativeTime) {
      var _props2 = this.props,
          isSeekable = _props2.isSeekable,
          onSeekStart = _props2.onSeekStart,
          totalTime = _props2.totalTime;


      if (isSeekable) {
        onSeekStart(relativeTime * totalTime);
      }
    }
  }, {
    key: 'handleSeekEnd',
    value: function handleSeekEnd(relativeTime) {
      var _props3 = this.props,
          isSeekable = _props3.isSeekable,
          onSeekEnd = _props3.onSeekEnd,
          totalTime = _props3.totalTime;


      if (isSeekable) {
        onSeekEnd(relativeTime * totalTime);
      }
    }
  }, {
    key: 'handleIntent',
    value: function handleIntent(relativeTime) {
      var _props4 = this.props,
          isSeekable = _props4.isSeekable,
          onIntent = _props4.onIntent,
          totalTime = _props4.totalTime;

      var intent = isSeekable ? relativeTime : 0;

      this.setState(_extends({}, this.state, {
        currentIntent: intent
      }));

      if (isSeekable) {
        onIntent(relativeTime * totalTime);
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      var _props5 = this.props,
          totalTime = _props5.totalTime,
          currentTime = _props5.currentTime,
          isSeekable = _props5.isSeekable,
          className = _props5.className,
          extraClasses = _props5.extraClasses,
          childClasses = _props5.childClasses,
          style = _props5.style,
          childrenStyles = _props5.childrenStyles;
      var currentIntent = this.state.currentIntent;


      var progressPercent = Math.min(100, 100 * currentTime / totalTime);
      var styleLeft = progressPercent + '%';

      var isRewindIntent = currentIntent !== 0 && currentIntent < currentTime / totalTime;

      return _react2.default.createElement(
        'div',
        {
          className: (0, _classnames2.default)(className, extraClasses, {
            isSeekable: isSeekable,
            isRewindIntent: isRewindIntent
          }),
          style: style,
          ref: this.storeRef
        },
        _react2.default.createElement('div', {
          className: childClasses.elapsed || 'ProgressBar-elapsed',
          style: _extends({ width: styleLeft }, childrenStyles.elapsed || {})
        }),
        _react2.default.createElement('div', {
          className: childClasses.intent || 'ProgressBar-intent',
          style: _extends({ width: currentIntent * 100 + '%' }, childrenStyles.intent || {})
        }),
        _react2.default.createElement('div', {
          className: childClasses.handle || 'ProgressBar-handle',
          style: _extends({ left: styleLeft }, childrenStyles.handle || {})
        }),
        isSeekable && _react2.default.createElement(_RangeControlOverlay2.default, {
          className: childClasses.seek || 'ProgressBar-seek',
          style: childrenStyles.RangeControlOverlay,
          bounds: function bounds() {
            return _this2.progressBarEl.getBoundingClientRect();
          },
          onValue: this.handleSeek,
          onChangeStart: this.handleSeekStart,
          onChangeEnd: this.handleSeekEnd,
          onIntent: this.handleIntent
        })
      );
    }
  }]);

  return ProgressBar;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'storeRef', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'storeRef'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleSeek', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleSeek'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleSeekStart', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleSeekStart'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleSeekEnd', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleSeekEnd'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleIntent', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleIntent'), _class.prototype)), _class);
ProgressBar.propTypes = {
  totalTime: number,
  currentTime: number,
  isSeekable: bool,
  onSeek: func,
  onSeekStart: func,
  onSeekEnd: func,
  onIntent: func,
  style: object
};
ProgressBar.defaultProps = {
  totalTime: Infinity,
  currentTime: 0,
  isSeekable: false,
  onSeek: function onSeek() {},
  onSeekStart: function onSeekStart() {},
  onSeekEnd: function onSeekEnd() {},
  onIntent: function onIntent() {},
  style: {}
};
exports.default = (0, _composers.compose)((0, _composers.withChildrenStyles)(), (0, _composers.withCustomizableClasses)('ProgressBar'), (0, _composers.withChildClasses)())(ProgressBar);

/***/ }),
/* 241 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TimeMarkerType = 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__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _collections = __webpack_require__(242);

var _composers = __webpack_require__(88);

var _FormattedTime = __webpack_require__(198);

var _FormattedTime2 = _interopRequireDefault(_FormattedTime);

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 number = _propTypes2.default.number,
    oneOf = _propTypes2.default.oneOf,
    string = _propTypes2.default.string,
    object = _propTypes2.default.object;

/**
 * Time marker types
 */

var TimeMarkerType = exports.TimeMarkerType = {
  ELAPSED: 'ELAPSED',
  LEFT: 'LEFT',
  LEFT_NEGATIVE: 'LEFT_NEGATIVE',
  DURATION: 'DURATION'

  /**
   * Composite component showing current and total time
   */
};
var TimeMarker = function (_Component) {
  _inherits(TimeMarker, _Component);

  function TimeMarker() {
    _classCallCheck(this, TimeMarker);

    return _possibleConstructorReturn(this, (TimeMarker.__proto__ || Object.getPrototypeOf(TimeMarker)).apply(this, arguments));
  }

  _createClass(TimeMarker, [{
    key: 'getSecondsForTimeWithMarkerType',
    value: function getSecondsForTimeWithMarkerType(markerType) {
      var _props = this.props,
          currentTime = _props.currentTime,
          totalTime = _props.totalTime;


      if (markerType === TimeMarkerType.DURATION) {
        return totalTime;
      } else if (markerType === TimeMarkerType.ELAPSED) {
        return currentTime;
      } else if (markerType === TimeMarkerType.LEFT) {
        return totalTime - currentTime;
      } else if (markerType === TimeMarkerType.LEFT_NEGATIVE) {
        return currentTime - totalTime;
      }

      return 0;
    }
  }, {
    key: 'render',
    value: function render() {
      var _props2 = this.props,
          firstMarkerType = _props2.firstMarkerType,
          secondMarkerType = _props2.secondMarkerType,
          markerSeparator = _props2.markerSeparator,
          className = _props2.className,
          extraClasses = _props2.extraClasses,
          childClasses = _props2.childClasses,
          style = _props2.style,
          childrenStyles = _props2.childrenStyles;


      var seconds1 = this.getSecondsForTimeWithMarkerType(firstMarkerType);
      var seconds2 = this.getSecondsForTimeWithMarkerType(secondMarkerType);

      return _react2.default.createElement(
        'div',
        {
          className: (0, _classnames2.default)(className, extraClasses),
          style: style
        },
        _react2.default.createElement(_FormattedTime2.default, {
          numSeconds: seconds1,
          extraClasses: (0, _classnames2.default)('TimeMarker-firstMarker', childClasses.firstMarker),
          style: childrenStyles.firstMarker
        }),
        markerSeparator && _react2.default.createElement(
          'span',
          {
            className: (0, _classnames2.default)('TimeMarker-separator', childClasses.separator),
            style: childrenStyles.separator
          },
          markerSeparator
        ),
        _react2.default.createElement(_FormattedTime2.default, {
          numSeconds: seconds2,
          extraClasses: (0, _classnames2.default)('TimeMarker-secondMarker', childClasses.secondMarker),
          style: childrenStyles.secondMarker
        })
      );
    }
  }]);

  return TimeMarker;
}(_react.Component);

TimeMarker.propTypes = {
  totalTime: number,
  currentTime: number,
  firstMarkerType: oneOf((0, _collections.values)(TimeMarkerType)),
  secondMarkerType: oneOf((0, _collections.values)(TimeMarkerType)),
  markerSeparator: string,
  style: object
};
TimeMarker.defaultProps = {
  totalTime: Infinity,
  currentTime: 0,
  firstMarkerType: TimeMarkerType.ELAPSED,
  secondMarkerType: TimeMarkerType.DURATION,
  markerSeparator: null,
  style: {}
};
exports.default = (0, _composers.compose)((0, _composers.withChildrenStyles)(), (0, _composers.withCustomizableClasses)('TimeMarker'), (0, _composers.withChildClasses)())(TimeMarker);

/***/ }),
/* 242 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
/**
 * Returns an array containing the values of an object literal
 */
var values = exports.values = function values(obj) {
  return Object.keys(obj).map(function (k) {
    return obj[k];
  });
};

/***/ }),
/* 243 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

var _composers = __webpack_require__(88);

var _SoundOnButton = __webpack_require__(199);

var _SoundOnButton2 = _interopRequireDefault(_SoundOnButton);

var _SoundOffButton = __webpack_require__(200);

var _SoundOffButton2 = _interopRequireDefault(_SoundOffButton);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

/**
 * Mute toggle button
 */
var MuteToggleButton = (_class = function (_Component) {
  _inherits(MuteToggleButton, _Component);

  function MuteToggleButton() {
    _classCallCheck(this, MuteToggleButton);

    return _possibleConstructorReturn(this, (MuteToggleButton.__proto__ || Object.getPrototypeOf(MuteToggleButton)).apply(this, arguments));
  }

  _createClass(MuteToggleButton, [{
    key: 'handleMuteChange',
    value: function handleMuteChange(isMuted) {
      if (this.props.isEnabled) {
        this.props.onMuteChange(isMuted);
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      var _props = this.props,
          isMuted = _props.isMuted,
          isEnabled = _props.isEnabled,
          className = _props.className,
          extraClasses = _props.extraClasses,
          childClasses = _props.childClasses,
          style = _props.style,
          childrenStyles = _props.childrenStyles;


      return _react2.default.createElement(
        'div',
        {
          className: (0, _classnames2.default)(className, extraClasses, { isMuted: isMuted, isEnabled: isEnabled }),
          style: style
        },
        isMuted ? _react2.default.createElement(_SoundOffButton2.default, {
          className: childClasses.SoundOffButton,
          style: childrenStyles.SoundOffButton,
          isEnabled: isEnabled,
          onClick: function onClick() {
            return _this2.handleMuteChange(false);
          }
        }) : _react2.default.createElement(_SoundOnButton2.default, {
          className: childClasses.SoundOnButton,
          style: childrenStyles.SoundOnButton,
          isEnabled: isEnabled,
          onClick: function onClick() {
            return _this2.handleMuteChange(true);
          }
        })
      );
    }
  }]);

  return MuteToggleButton;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'handleMuteChange', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleMuteChange'), _class.prototype)), _class);
MuteToggleButton.propTypes = {
  onMuteChange: _propTypes2.default.func.isRequired,
  isMuted: _propTypes2.default.bool,
  isEnabled: _propTypes2.default.bool,
  className: _propTypes2.default.string,
  extraClasses: _propTypes2.default.string,
  style: _propTypes2.default.object
};
MuteToggleButton.defaultProps = {
  isMuted: false,
  isEnabled: true,
  className: 'MuteToggleButton',
  extraClasses: '',
  style: {}
};
exports.default = (0, _composers.withChildClasses)((0, _composers.withChildrenStyles)(MuteToggleButton));

/***/ }),
/* 244 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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 _desc, _value, _class;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _autobindDecorator = __webpack_require__(89);

var _autobindDecorator2 = _interopRequireDefault(_autobindDecorator);

var _classnames = __webpack_require__(84);

var _classnames2 = _interopRequireDefault(_classnames);

var _composers = __webpack_require__(88);

var _RangeControlOverlay = __webpack_require__(197);

var _RangeControlOverlay2 = _interopRequireDefault(_RangeControlOverlay);

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; }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

var number = _propTypes2.default.number,
    bool = _propTypes2.default.bool,
    func = _propTypes2.default.func,
    string = _propTypes2.default.string,
    object = _propTypes2.default.object;

/**
 * Volume slider component
 */

var VolumeSlider = (_class = function (_Component) {
  _inherits(VolumeSlider, _Component);

  function VolumeSlider(props) {
    _classCallCheck(this, VolumeSlider);

    var _this = _possibleConstructorReturn(this, (VolumeSlider.__proto__ || Object.getPrototypeOf(VolumeSlider)).call(this, props));

    _this.sliderEl = null;

    _this.state = {
      currentIntent: 0
    };
    return _this;
  }

  _createClass(VolumeSlider, [{
    key: 'storeRef',
    value: function storeRef(rootEl) {
      this.sliderEl = rootEl;
    }
  }, {
    key: 'getBounds',
    value: function getBounds() {
      return this.sliderEl.getBoundingClientRect();
    }
  }, {
    key: 'handleVolumeChange',
    value: function handleVolumeChange(volume) {
      var _props = this.props,
          isEnabled = _props.isEnabled,
          onVolumeChange = _props.onVolumeChange;


      if (isEnabled) {
        onVolumeChange(volume);
      }
    }
  }, {
    key: 'handleIntent',
    value: function handleIntent(volume) {
      var intent = this.props.isEnabled ? volume : 0;

      this.setState({
        currentIntent: intent
      });
    }
  }, {
    key: 'render',
    value: function render() {
      var _props2 = this.props,
          volume = _props2.volume,
          isEnabled = _props2.isEnabled,
          className = _props2.className,
          extraClasses = _props2.extraClasses,
          childClasses = _props2.childClasses,
          style = _props2.style,
          childrenStyles = _props2.childrenStyles;
      var currentIntent = this.state.currentIntent;


      var volumePercentage = Math.min(100, Math.max(0, volume * 100));
      var styleBottom = volumePercentage + '%';

      var appliedIntent = isEnabled && currentIntent !== 0 ? currentIntent : 0;
      var isDecreaseIntent = appliedIntent && currentIntent < volume;

      return _react2.default.createElement(
        'div',
        {
          className: (0, _classnames2.default)(className, extraClasses, {
            isEnabled: isEnabled,
            isDecreaseIntent: isDecreaseIntent
          }),
          style: style,
          ref: this.storeRef
        },
        _react2.default.createElement('div', {
          className: childClasses.value || 'VolumeSlider-value',
          style: _extends({ height: styleBottom }, childrenStyles.value || {})
        }),
        _react2.default.createElement('div', {
          className: childClasses.intent || 'VolumeSlider-intent',
          style: _extends({ height: appliedIntent * 100 + '%' }, childrenStyles.intent || {})
        }),
        _react2.default.createElement('div', {
          className: childClasses.handle || 'VolumeSlider-handle',
          style: _extends({ bottom: styleBottom }, childrenStyles.handle || {})
        }),
        isEnabled && _react2.default.createElement(_RangeControlOverlay2.default, {
          extraClasses: childClasses.seek || 'VolumeSlider-seek',
          style: childrenStyles.RangeControlOverlay,
          bounds: this.getBounds,
          direction: _RangeControlOverlay.ControlDirection.VERTICAL,
          onValue: this.handleVolumeChange,
          onIntent: this.handleIntent
        })
      );
    }
  }]);

  return VolumeSlider;
}(_react.Component), (_applyDecoratedDescriptor(_class.prototype, 'storeRef', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'storeRef'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'getBounds', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'getBounds'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleVolumeChange', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleVolumeChange'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'handleIntent', [_autobindDecorator2.default], Object.getOwnPropertyDescriptor(_class.prototype, 'handleIntent'), _class.prototype)), _class);
VolumeSlider.propTypes = {
  volume: number,
  isEnabled: bool,
  onVolumeChange: func,
  extraClasses: string,
  style: object
};
VolumeSlider.defaultProps = {
  volume: 0,
  isEnabled: false,
  onVolumeChange: function onVolumeChange() {},
  extraClasses: '',
  style: {}
};
exports.default = (0, _composers.compose)((0, _composers.withChildrenStyles)(), (0, _composers.withCustomizableClasses)('VolumeSlider'), (0, _composers.withChildClasses)())(VolumeSlider);

/***/ }),
/* 245 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.horizontalCenter = exports.Icon = exports.withBaseIcon = undefined;

var _Icon = __webpack_require__(246);

var _horizontalCenter = __webpack_require__(255);

exports.withBaseIcon = _Icon.withBaseIcon;
exports.Icon = _Icon.Icon;
exports.horizontalCenter = _horizontalCenter.horizontalCenter;
exports.default = _Icon.Icon;

/***/ }),
/* 246 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.withBaseIcon = exports.Icon = 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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _SvgIcon = __webpack_require__(247);

var _SvgIcon2 = _interopRequireDefault(_SvgIcon);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }

var Icon = function Icon(props) {
    var style = props.style,
        className = props.className,
        icon = props.icon,
        others = _objectWithoutProperties(props, ['style', 'className', 'icon']); //eslint-disable-line

    return _react2.default.createElement(
        'div',
        _extends({}, others, { style: _extends({}, style, { display: 'inline-flex', justifyContent: 'center', alignItems: 'center' }), className: className }),
        _react2.default.createElement(_SvgIcon2.default, { size: props.size, icon: props.icon })
    );
};

exports.Icon = Icon;
var withBaseIcon = exports.withBaseIcon = function withBaseIcon(defaultProps) {
    return function (props) {
        var propsToUse = _extends({}, defaultProps);

        return _react2.default.createElement(Icon, _extends({}, propsToUse, props));
    };
};

Icon.defaultProps = {
    size: 16,
    fill: 'currentColor'
};

Icon.propTypes = {
    icon: _propTypes2.default.object.isRequired,
    size: _propTypes2.default.number,
    style: _propTypes2.default.object,
    className: _propTypes2.default.string
};

exports.default = Icon;

/***/ }),
/* 247 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.SvgIcon = 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 _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _camelCase = __webpack_require__(248);

var _camelCase2 = _interopRequireDefault(_camelCase);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var walkChildren = function walkChildren(children) {
    return children.map(function (child, idx) {
        var name = child.name,
            attribsMap = child.attribs,
            _child$children = child.children,
            gchildren = _child$children === undefined ? null : _child$children;

        //fill, stroke

        var attribs = Object.keys(attribsMap).filter(function (key) {
            return key !== 'fill' && key !== 'stroke' && attribsMap[key] !== 'none';
        }).reduce(function (partial, key) {

            partial[(0, _camelCase2.default)(key)] = attribsMap[key];
            return partial;
        }, {});
        //special case, it has fill and stroke at the same time
        var merge = {};
        if (attribsMap.fill === 'none' && attribsMap.stroke) {
            merge = { fill: 'none', stroke: 'currentColor' };
        }
        return (0, _react.createElement)(name, _extends({ key: idx }, attribs, merge), gchildren === null ? gchildren : walkChildren(gchildren));
    });
};

var SvgIcon = exports.SvgIcon = function SvgIcon(props) {
    var size = props.size;
    var _props$icon = props.icon,
        children = _props$icon.children,
        viewBox = _props$icon.viewBox;

    return _react2.default.createElement(
        'svg',
        { fill: 'currentColor', style: { display: 'inline-block', verticalAlign: 'middle' }, height: size, width: size, viewBox: viewBox },
        walkChildren(children)
    );
};

SvgIcon.defaultProps = {
    size: '16'
};

SvgIcon.propTypes = {
    icon: _propTypes2.default.object.isRequired,
    size: _propTypes2.default.number
};

exports.default = SvgIcon;

/***/ }),
/* 248 */
/***/ (function(module, exports, __webpack_require__) {

var upperCase = __webpack_require__(249)
var noCase = __webpack_require__(250)

/**
 * Camel case a string.
 *
 * @param  {string} value
 * @param  {string} [locale]
 * @return {string}
 */
module.exports = function (value, locale, mergeNumbers) {
  var result = noCase(value, locale)

  // Replace periods between numeric entities with an underscore.
  if (!mergeNumbers) {
    result = result.replace(/ (?=\d)/g, '_')
  }

  // Replace spaces between words with an upper cased character.
  return result.replace(/ (.)/g, function (m, $1) {
    return upperCase($1, locale)
  })
}


/***/ }),
/* 249 */
/***/ (function(module, exports) {

/**
 * Special language-specific overrides.
 *
 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
 *
 * @type {Object}
 */
var LANGUAGES = {
  tr: {
    regexp: /[\u0069]/g,
    map: {
      '\u0069': '\u0130'
    }
  },
  az: {
    regexp: /[\u0069]/g,
    map: {
      '\u0069': '\u0130'
    }
  },
  lt: {
    regexp: /[\u0069\u006A\u012F]\u0307|\u0069\u0307[\u0300\u0301\u0303]/g,
    map: {
      '\u0069\u0307': '\u0049',
      '\u006A\u0307': '\u004A',
      '\u012F\u0307': '\u012E',
      '\u0069\u0307\u0300': '\u00CC',
      '\u0069\u0307\u0301': '\u00CD',
      '\u0069\u0307\u0303': '\u0128'
    }
  }
}

/**
 * Upper case a string.
 *
 * @param  {String} str
 * @return {String}
 */
module.exports = function (str, locale) {
  var lang = LANGUAGES[locale]

  str = str == null ? '' : String(str)

  if (lang) {
    str = str.replace(lang.regexp, function (m) { return lang.map[m] })
  }

  return str.toUpperCase()
}


/***/ }),
/* 250 */
/***/ (function(module, exports, __webpack_require__) {

var lowerCase = __webpack_require__(251)

var NON_WORD_REGEXP = __webpack_require__(252)
var CAMEL_CASE_REGEXP = __webpack_require__(253)
var CAMEL_CASE_UPPER_REGEXP = __webpack_require__(254)

/**
 * Sentence case a string.
 *
 * @param  {string} str
 * @param  {string} locale
 * @param  {string} replacement
 * @return {string}
 */
module.exports = function (str, locale, replacement) {
  if (str == null) {
    return ''
  }

  replacement = typeof replacement !== 'string' ? ' ' : replacement

  function replace (match, index, value) {
    if (index === 0 || index === (value.length - match.length)) {
      return ''
    }

    return replacement
  }

  str = String(str)
    // Support camel case ("camelCase" -> "camel Case").
    .replace(CAMEL_CASE_REGEXP, '$1 $2')
    // Support odd camel case ("CAMELCase" -> "CAMEL Case").
    .replace(CAMEL_CASE_UPPER_REGEXP, '$1 $2')
    // Remove all non-word characters and replace with a single space.
    .replace(NON_WORD_REGEXP, replace)

  // Lower case the entire string.
  return lowerCase(str, locale)
}


/***/ }),
/* 251 */
/***/ (function(module, exports) {

/**
 * Special language-specific overrides.
 *
 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
 *
 * @type {Object}
 */
var LANGUAGES = {
  tr: {
    regexp: /\u0130|\u0049|\u0049\u0307/g,
    map: {
      '\u0130': '\u0069',
      '\u0049': '\u0131',
      '\u0049\u0307': '\u0069'
    }
  },
  az: {
    regexp: /[\u0130]/g,
    map: {
      '\u0130': '\u0069',
      '\u0049': '\u0131',
      '\u0049\u0307': '\u0069'
    }
  },
  lt: {
    regexp: /[\u0049\u004A\u012E\u00CC\u00CD\u0128]/g,
    map: {
      '\u0049': '\u0069\u0307',
      '\u004A': '\u006A\u0307',
      '\u012E': '\u012F\u0307',
      '\u00CC': '\u0069\u0307\u0300',
      '\u00CD': '\u0069\u0307\u0301',
      '\u0128': '\u0069\u0307\u0303'
    }
  }
}

/**
 * Lowercase a string.
 *
 * @param  {String} str
 * @return {String}
 */
module.exports = function (str, locale) {
  var lang = LANGUAGES[locale]

  str = str == null ? '' : String(str)

  if (lang) {
    str = str.replace(lang.regexp, function (m) { return lang.map[m] })
  }

  return str.toLowerCase()
}


/***/ }),
/* 252 */
/***/ (function(module, exports) {

module.exports = /[^A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19]+/g


/***/ }),
/* 253 */
/***/ (function(module, exports) {

module.exports = /([a-z\xB5\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19])([A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AD\uA7B0-\uA7B4\uA7B6\uFF21-\uFF3A])/g


/***/ }),
/* 254 */
/***/ (function(module, exports) {

module.exports = /([A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AD\uA7B0-\uA7B4\uA7B6\uFF21-\uFF3A])([A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AD\uA7B0-\uA7B4\uA7B6\uFF21-\uFF3A][a-z\xB5\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A])/g


/***/ }),
/* 255 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.horizontalCenter = undefined;

var _react = __webpack_require__(11);

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var horizontalCenter = exports.horizontalCenter = function horizontalCenter(Component) {
    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
        _ref$rAlign = _ref.rAlign,
        rAlign = _ref$rAlign === undefined ? false : _ref$rAlign,
        _ref$space = _ref.space,
        space = _ref$space === undefined ? 4 : _ref$space;

    return function (props) {

        return _react2.default.createElement(
            Component,
            props,
            _react2.default.createElement(
                'div',
                { style: { display: 'inline-flex', justifyContent: 'center', 'alignItems': 'center' } },
                _react.Children.toArray(props.children).map(function (child, idx) {
                    var spacerField = rAlign ? 'paddingLeft' : 'paddingRight';
                    return _react2.default.createElement(
                        'div',
                        { key: idx, style: _defineProperty({ display: 'inline-block' }, spacerField, space) },
                        child
                    );
                })
            )
        );
    };
};

exports.default = horizontalCenter;

/***/ }),
/* 256 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
var play = exports.play = { "viewBox": "0 0 1408 1792", "children": [{ "name": "path", "attribs": { "d": "M1384 927l-1328 738q-23 13-39.5 3t-16.5-36v-1472q0-26 16.5-36t39.5 3l1328 738q23 13 23 31t-23 31z" } }] };

/***/ }),
/* 257 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
var pause = exports.pause = { "viewBox": "0 0 1536 1792", "children": [{ "name": "path", "attribs": { "d": "M1536 192v1408q0 26-19 45t-45 19h-512q-26 0-45-19t-19-45v-1408q0-26 19-45t45-19h512q26 0 45 19t19 45zM640 192v1408q0 26-19 45t-45 19h-512q-26 0-45-19t-19-45v-1408q0-26 19-45t45-19h512q26 0 45 19t19 45z" } }] };

/***/ }),
/* 258 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
var copy = exports.copy = { "viewBox": "0 0 1792 1792", "children": [{ "name": "path", "attribs": { "d": "M1696 384q40 0 68 28t28 68v1216q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-288h-544q-40 0-68-28t-28-68v-672q0-40 20-88t48-76l408-408q28-28 76-48t88-20h416q40 0 68 28t28 68v328q68-40 128-40h416zM1152 597l-299 299h299v-299zM512 213l-299 299h299v-299zM708 860l316-316v-416h-384v416q0 40-28 68t-68 28h-416v640h512v-256q0-40 20-88t48-76zM1664 1664v-1152h-384v416q0 40-28 68t-68 28h-416v640h896z" } }] };

/***/ }),
/* 259 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
var heart = exports.heart = { "viewBox": "0 0 1792 1792", "children": [{ "name": "path", "attribs": { "d": "M896 1664q-26 0-44-18l-624-602q-10-8-27.5-26t-55.5-65.5-68-97.5-53.5-121-23.5-138q0-220 127-344t351-124q62 0 126.5 21.5t120 58 95.5 68.5 76 68q36-36 76-68t95.5-68.5 120-58 126.5-21.5q224 0 351 124t127 344q0 221-229 450l-623 600q-18 18-44 18z" } }] };

/***/ }),
/* 260 */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ }),
/* 261 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


exports.__esModule = true;

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; }

exports.default = function (_ref) {
    var _class, _temp2;

    var Component = _ref.Component,
        createElement = _ref.createElement;
    return _temp2 = _class = function (_Component) {
        _inherits(ReactHint, _Component);

        function ReactHint() {
            var _temp, _this, _ret;

            _classCallCheck(this, ReactHint);

            for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
                args[_key] = arguments[_key];
            }

            return _ret = (_temp = (_this = _possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = { target: null }, _this._containerStyle = { position: 'relative' }, _this.toggleEvents = function (_ref2, flag) {
                var events = _ref2.events,
                    _ref2$events = _ref2.events,
                    click = _ref2$events.click,
                    focus = _ref2$events.focus,
                    hover = _ref2$events.hover;

                var action = flag ? 'addEventListener' : 'removeEventListener';
                var hasEvents = events === true;(click || hasEvents) && document[action]('click', _this.toggleHint);(focus || hasEvents) && document[action]('focusin', _this.toggleHint);(hover || hasEvents) && document[action]('mouseover', _this.toggleHint);(click || hover || hasEvents) && document[action]('touchend', _this.toggleHint);
            }, _this.toggleHint = function () {
                var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
                    _ref3$target = _ref3.target,
                    target = _ref3$target === undefined ? null : _ref3$target;

                clearTimeout(_this._timeout);
                _this._timeout = setTimeout(function () {
                    return _this.setState(function () {
                        return {
                            target: _this.getHint(target)
                        };
                    });
                }, _this.props.delay);
            }, _this.getHint = function (el) {
                var _this$props = _this.props,
                    attribute = _this$props.attribute,
                    persist = _this$props.persist;
                var target = _this.state.target;


                while (el) {
                    if (el === document) break;
                    if (persist && el === _this._hint) return target;
                    if (el.hasAttribute(attribute)) return el;
                    el = el.parentNode;
                }return null;
            }, _this.shallowEqual = function (a, b) {
                var keys = Object.keys(a);
                return keys.length === Object.keys(b).length && keys.reduce(function (result, key) {
                    return result && (typeof a[key] === 'function' && typeof b[key] === 'function' || a[key] === b[key]);
                }, true);
            }, _this.getHintData = function (_ref4, _ref5) {
                var target = _ref4.target;
                var attribute = _ref5.attribute,
                    position = _ref5.position;

                var content = target.getAttribute(attribute) || '';
                var at = target.getAttribute(attribute + '-at') || position;

                var _this$_container$getB = _this._container.getBoundingClientRect(),
                    containerTop = _this$_container$getB.top,
                    containerLeft = _this$_container$getB.left;

                var _this$_hint$getBoundi = _this._hint.getBoundingClientRect(),
                    hintWidth = _this$_hint$getBoundi.width,
                    hintHeight = _this$_hint$getBoundi.height;

                var _target$getBoundingCl = target.getBoundingClientRect(),
                    targetTop = _target$getBoundingCl.top,
                    targetLeft = _target$getBoundingCl.left,
                    targetWidth = _target$getBoundingCl.width,
                    targetHeight = _target$getBoundingCl.height;

                var top = void 0,
                    left = void 0;
                switch (at) {
                    case 'left':
                        top = targetHeight - hintHeight >> 1;
                        left = -hintWidth;
                        break;

                    case 'right':
                        top = targetHeight - hintHeight >> 1;
                        left = targetWidth;
                        break;

                    case 'bottom':
                        top = targetHeight;
                        left = targetWidth - hintWidth >> 1;
                        break;

                    case 'top':
                    default:
                        top = -hintHeight;
                        left = targetWidth - hintWidth >> 1;
                }

                return {
                    content: content, at: at,
                    top: top + targetTop - containerTop,
                    left: left + targetLeft - containerLeft
                };
            }, _temp), _possibleConstructorReturn(_this, _ret);
        }

        ReactHint.prototype.componentDidMount = function componentDidMount() {
            this.toggleEvents(this.props, true);
        };

        ReactHint.prototype.componentWillUnmount = function componentWillUnmount() {
            this.toggleEvents(this.props, false);
            clearTimeout(this._timeout);
        };

        ReactHint.prototype.shouldComponentUpdate = function shouldComponentUpdate(props, state) {
            return !this.shallowEqual(state, this.state) || !this.shallowEqual(props, this.props);
        };

        ReactHint.prototype.componentDidUpdate = function componentDidUpdate() {
            if (this.state.target) this.setState(this.getHintData);
        };

        ReactHint.prototype.render = function render() {
            var _this2 = this;

            var _props = this.props,
                className = _props.className,
                onRenderContent = _props.onRenderContent;
            var _state = this.state,
                target = _state.target,
                content = _state.content,
                at = _state.at,
                top = _state.top,
                left = _state.left;


            return createElement(
                'div',
                { ref: function ref(_ref7) {
                        return _this2._container = _ref7;
                    },
                    style: this._containerStyle },
                target && createElement(
                    'div',
                    { className: className + ' ' + className + '--' + at,
                        ref: function ref(_ref6) {
                            return _this2._hint = _ref6;
                        },
                        style: { top: top, left: left } },
                    onRenderContent ? onRenderContent(target, content) : createElement(
                        'div',
                        { className: className + '__content' },
                        content
                    )
                )
            );
        };

        return ReactHint;
    }(Component), _class.defaultProps = {
        attribute: 'data-rh',
        className: 'react-hint',
        delay: 0,
        events: false,
        onRenderContent: null,
        persist: false,
        position: 'top'
    }, _temp2;
};

module.exports = exports['default'];

/***/ }),
/* 262 */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ }),
/* 263 */
/***/ (function(module, exports, __webpack_require__) {

module.exports = __webpack_require__(264);

/***/ }),
/* 264 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);
var bind = __webpack_require__(203);
var Axios = __webpack_require__(266);
var defaults = __webpack_require__(191);

/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  var instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context);

  return instance;
}

// Create the default instance to be exported
var axios = createInstance(defaults);

// Expose Axios class to allow class inheritance
axios.Axios = Axios;

// Factory for creating new instances
axios.create = function create(instanceConfig) {
  return createInstance(utils.merge(defaults, instanceConfig));
};

// Expose Cancel & CancelToken
axios.Cancel = __webpack_require__(207);
axios.CancelToken = __webpack_require__(280);
axios.isCancel = __webpack_require__(206);

// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = __webpack_require__(281);

module.exports = axios;

// Allow use of default import syntax in TypeScript
module.exports.default = axios;


/***/ }),
/* 265 */
/***/ (function(module, exports) {

/*!
 * Determine if an object is a Buffer
 *
 * @author   Feross Aboukhadijeh <https://feross.org>
 * @license  MIT
 */

// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
  return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}

function isBuffer (obj) {
  return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}

// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
  return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}


/***/ }),
/* 266 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var defaults = __webpack_require__(191);
var utils = __webpack_require__(34);
var InterceptorManager = __webpack_require__(275);
var dispatchRequest = __webpack_require__(276);

/**
 * Create a new instance of Axios
 *
 * @param {Object} instanceConfig The default config for the instance
 */
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

/**
 * Dispatch a request
 *
 * @param {Object} config The config specific for this request (merged with this.defaults)
 */
Axios.prototype.request = function request(config) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  if (typeof config === 'string') {
    config = utils.merge({
      url: arguments[0]
    }, arguments[1]);
  }

  config = utils.merge(defaults, this.defaults, { method: 'get' }, config);
  config.method = config.method.toLowerCase();

  // Hook up interceptors middleware
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);

  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

  return promise;
};

// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

module.exports = Axios;


/***/ }),
/* 267 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

module.exports = function normalizeHeaderName(headers, normalizedName) {
  utils.forEach(headers, function processHeader(value, name) {
    if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
      headers[normalizedName] = value;
      delete headers[name];
    }
  });
};


/***/ }),
/* 268 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var createError = __webpack_require__(205);

/**
 * Resolve or reject a Promise based on response status.
 *
 * @param {Function} resolve A function that resolves the promise.
 * @param {Function} reject A function that rejects the promise.
 * @param {object} response The response.
 */
module.exports = function settle(resolve, reject, response) {
  var validateStatus = response.config.validateStatus;
  // Note: status is not exposed by XDomainRequest
  if (!response.status || !validateStatus || validateStatus(response.status)) {
    resolve(response);
  } else {
    reject(createError(
      'Request failed with status code ' + response.status,
      response.config,
      null,
      response.request,
      response
    ));
  }
};


/***/ }),
/* 269 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Update an Error with the specified config, error code, and response.
 *
 * @param {Error} error The error to update.
 * @param {Object} config The config.
 * @param {string} [code] The error code (for example, 'ECONNABORTED').
 * @param {Object} [request] The request.
 * @param {Object} [response] The response.
 * @returns {Error} The error.
 */
module.exports = function enhanceError(error, config, code, request, response) {
  error.config = config;
  if (code) {
    error.code = code;
  }
  error.request = request;
  error.response = response;
  return error;
};


/***/ }),
/* 270 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

function encode(val) {
  return encodeURIComponent(val).
    replace(/%40/gi, '@').
    replace(/%3A/gi, ':').
    replace(/%24/g, '$').
    replace(/%2C/gi, ',').
    replace(/%20/g, '+').
    replace(/%5B/gi, '[').
    replace(/%5D/gi, ']');
}

/**
 * Build a URL by appending params to the end
 *
 * @param {string} url The base of the url (e.g., http://www.google.com)
 * @param {object} [params] The params to be appended
 * @returns {string} The formatted url
 */
module.exports = function buildURL(url, params, paramsSerializer) {
  /*eslint no-param-reassign:0*/
  if (!params) {
    return url;
  }

  var serializedParams;
  if (paramsSerializer) {
    serializedParams = paramsSerializer(params);
  } else if (utils.isURLSearchParams(params)) {
    serializedParams = params.toString();
  } else {
    var parts = [];

    utils.forEach(params, function serialize(val, key) {
      if (val === null || typeof val === 'undefined') {
        return;
      }

      if (utils.isArray(val)) {
        key = key + '[]';
      }

      if (!utils.isArray(val)) {
        val = [val];
      }

      utils.forEach(val, function parseValue(v) {
        if (utils.isDate(v)) {
          v = v.toISOString();
        } else if (utils.isObject(v)) {
          v = JSON.stringify(v);
        }
        parts.push(encode(key) + '=' + encode(v));
      });
    });

    serializedParams = parts.join('&');
  }

  if (serializedParams) {
    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
  }

  return url;
};


/***/ }),
/* 271 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

// Headers whose duplicates are ignored by node
// c.f. https://nodejs.org/api/http.html#http_message_headers
var ignoreDuplicateOf = [
  'age', 'authorization', 'content-length', 'content-type', 'etag',
  'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',
  'last-modified', 'location', 'max-forwards', 'proxy-authorization',
  'referer', 'retry-after', 'user-agent'
];

/**
 * Parse headers into an object
 *
 * ```
 * Date: Wed, 27 Aug 2014 08:58:49 GMT
 * Content-Type: application/json
 * Connection: keep-alive
 * Transfer-Encoding: chunked
 * ```
 *
 * @param {String} headers Headers needing to be parsed
 * @returns {Object} Headers parsed into an object
 */
module.exports = function parseHeaders(headers) {
  var parsed = {};
  var key;
  var val;
  var i;

  if (!headers) { return parsed; }

  utils.forEach(headers.split('\n'), function parser(line) {
    i = line.indexOf(':');
    key = utils.trim(line.substr(0, i)).toLowerCase();
    val = utils.trim(line.substr(i + 1));

    if (key) {
      if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
        return;
      }
      if (key === 'set-cookie') {
        parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
      } else {
        parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
      }
    }
  });

  return parsed;
};


/***/ }),
/* 272 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

module.exports = (
  utils.isStandardBrowserEnv() ?

  // Standard browser envs have full support of the APIs needed to test
  // whether the request URL is of the same origin as current location.
  (function standardBrowserEnv() {
    var msie = /(msie|trident)/i.test(navigator.userAgent);
    var urlParsingNode = document.createElement('a');
    var originURL;

    /**
    * Parse a URL to discover it's components
    *
    * @param {String} url The URL to be parsed
    * @returns {Object}
    */
    function resolveURL(url) {
      var href = url;

      if (msie) {
        // IE needs attribute set twice to normalize properties
        urlParsingNode.setAttribute('href', href);
        href = urlParsingNode.href;
      }

      urlParsingNode.setAttribute('href', href);

      // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
      return {
        href: urlParsingNode.href,
        protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
        host: urlParsingNode.host,
        search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
        hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
        hostname: urlParsingNode.hostname,
        port: urlParsingNode.port,
        pathname: (urlParsingNode.pathname.charAt(0) === '/') ?
                  urlParsingNode.pathname :
                  '/' + urlParsingNode.pathname
      };
    }

    originURL = resolveURL(window.location.href);

    /**
    * Determine if a URL shares the same origin as the current location
    *
    * @param {String} requestURL The URL to test
    * @returns {boolean} True if URL shares the same origin, otherwise false
    */
    return function isURLSameOrigin(requestURL) {
      var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;
      return (parsed.protocol === originURL.protocol &&
            parsed.host === originURL.host);
    };
  })() :

  // Non standard browser envs (web workers, react-native) lack needed support.
  (function nonStandardBrowserEnv() {
    return function isURLSameOrigin() {
      return true;
    };
  })()
);


/***/ }),
/* 273 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


// btoa polyfill for IE<10 courtesy https://github.com/davidchambers/Base64.js

var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

function E() {
  this.message = 'String contains an invalid character';
}
E.prototype = new Error;
E.prototype.code = 5;
E.prototype.name = 'InvalidCharacterError';

function btoa(input) {
  var str = String(input);
  var output = '';
  for (
    // initialize result and counter
    var block, charCode, idx = 0, map = chars;
    // if the next str index does not exist:
    //   change the mapping table to "="
    //   check if d has no fractional digits
    str.charAt(idx | 0) || (map = '=', idx % 1);
    // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
    output += map.charAt(63 & block >> 8 - idx % 1 * 8)
  ) {
    charCode = str.charCodeAt(idx += 3 / 4);
    if (charCode > 0xFF) {
      throw new E();
    }
    block = block << 8 | charCode;
  }
  return output;
}

module.exports = btoa;


/***/ }),
/* 274 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

module.exports = (
  utils.isStandardBrowserEnv() ?

  // Standard browser envs support document.cookie
  (function standardBrowserEnv() {
    return {
      write: function write(name, value, expires, path, domain, secure) {
        var cookie = [];
        cookie.push(name + '=' + encodeURIComponent(value));

        if (utils.isNumber(expires)) {
          cookie.push('expires=' + new Date(expires).toGMTString());
        }

        if (utils.isString(path)) {
          cookie.push('path=' + path);
        }

        if (utils.isString(domain)) {
          cookie.push('domain=' + domain);
        }

        if (secure === true) {
          cookie.push('secure');
        }

        document.cookie = cookie.join('; ');
      },

      read: function read(name) {
        var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
        return (match ? decodeURIComponent(match[3]) : null);
      },

      remove: function remove(name) {
        this.write(name, '', Date.now() - 86400000);
      }
    };
  })() :

  // Non standard browser env (web workers, react-native) lack needed support.
  (function nonStandardBrowserEnv() {
    return {
      write: function write() {},
      read: function read() { return null; },
      remove: function remove() {}
    };
  })()
);


/***/ }),
/* 275 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

function InterceptorManager() {
  this.handlers = [];
}

/**
 * Add a new interceptor to the stack
 *
 * @param {Function} fulfilled The function to handle `then` for a `Promise`
 * @param {Function} rejected The function to handle `reject` for a `Promise`
 *
 * @return {Number} An ID used to remove interceptor later
 */
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};

/**
 * Remove an interceptor from the stack
 *
 * @param {Number} id The ID that was returned by `use`
 */
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null;
  }
};

/**
 * Iterate over all the registered interceptors
 *
 * This method is particularly useful for skipping over any
 * interceptors that may have become `null` calling `eject`.
 *
 * @param {Function} fn The function to call for each interceptor
 */
InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      fn(h);
    }
  });
};

module.exports = InterceptorManager;


/***/ }),
/* 276 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);
var transformData = __webpack_require__(277);
var isCancel = __webpack_require__(206);
var defaults = __webpack_require__(191);
var isAbsoluteURL = __webpack_require__(278);
var combineURLs = __webpack_require__(279);

/**
 * Throws a `Cancel` if cancellation has been requested.
 */
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    config.cancelToken.throwIfRequested();
  }
}

/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */
module.exports = function dispatchRequest(config) {
  throwIfCancellationRequested(config);

  // Support baseURL config
  if (config.baseURL && !isAbsoluteURL(config.url)) {
    config.url = combineURLs(config.baseURL, config.url);
  }

  // Ensure headers exist
  config.headers = config.headers || {};

  // Transform request data
  config.data = transformData(
    config.data,
    config.headers,
    config.transformRequest
  );

  // Flatten headers
  config.headers = utils.merge(
    config.headers.common || {},
    config.headers[config.method] || {},
    config.headers || {}
  );

  utils.forEach(
    ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
    function cleanHeaderConfig(method) {
      delete config.headers[method];
    }
  );

  var adapter = config.adapter || defaults.adapter;

  return adapter(config).then(function onAdapterResolution(response) {
    throwIfCancellationRequested(config);

    // Transform response data
    response.data = transformData(
      response.data,
      response.headers,
      config.transformResponse
    );

    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      throwIfCancellationRequested(config);

      // Transform response data
      if (reason && reason.response) {
        reason.response.data = transformData(
          reason.response.data,
          reason.response.headers,
          config.transformResponse
        );
      }
    }

    return Promise.reject(reason);
  });
};


/***/ }),
/* 277 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var utils = __webpack_require__(34);

/**
 * Transform the data for a request or a response
 *
 * @param {Object|String} data The data to be transformed
 * @param {Array} headers The headers for the request or response
 * @param {Array|Function} fns A single function or Array of functions
 * @returns {*} The resulting transformed data
 */
module.exports = function transformData(data, headers, fns) {
  /*eslint no-param-reassign:0*/
  utils.forEach(fns, function transform(fn) {
    data = fn(data, headers);
  });

  return data;
};


/***/ }),
/* 278 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Determines whether the specified URL is absolute
 *
 * @param {string} url The URL to test
 * @returns {boolean} True if the specified URL is absolute, otherwise false
 */
module.exports = function isAbsoluteURL(url) {
  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
  // by any combination of letters, digits, plus, period, or hyphen.
  return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
};


/***/ }),
/* 279 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Creates a new URL by combining the specified URLs
 *
 * @param {string} baseURL The base URL
 * @param {string} relativeURL The relative URL
 * @returns {string} The combined URL
 */
module.exports = function combineURLs(baseURL, relativeURL) {
  return relativeURL
    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
    : baseURL;
};


/***/ }),
/* 280 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var Cancel = __webpack_require__(207);

/**
 * A `CancelToken` is an object that can be used to request cancellation of an operation.
 *
 * @class
 * @param {Function} executor The executor function.
 */
function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

/**
 * Throws a `Cancel` if cancellation has been requested.
 */
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

/**
 * Returns an object that contains a new `CancelToken` and a function that, when called,
 * cancels the `CancelToken`.
 */
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

module.exports = CancelToken;


/***/ }),
/* 281 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Syntactic sugar for invoking a function and expanding an array for arguments.
 *
 * Common use case would be to use `Function.prototype.apply`.
 *
 *  ```js
 *  function f(x, y, z) {}
 *  var args = [1, 2, 3];
 *  f.apply(null, args);
 *  ```
 *
 * With `spread` this example can be re-written.
 *
 *  ```js
 *  spread(function(x, y, z) {})([1, 2, 3]);
 *  ```
 *
 * @param {Function} callback
 * @returns {Function}
 */
module.exports = function spread(callback) {
  return function wrap(arr) {
    return callback.apply(null, arr);
  };
};


/***/ }),
/* 282 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

var _skylight = __webpack_require__(283);

Object.defineProperty(exports, 'default', {
  enumerable: true,
  get: function get() {
    return _interopRequireDefault(_skylight).default;
  }
});

var _skylightstateless = __webpack_require__(208);

Object.defineProperty(exports, 'SkyLightStateless', {
  enumerable: true,
  get: function get() {
    return _interopRequireDefault(_skylightstateless).default;
  }
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/***/ }),
/* 283 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

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__(11);

var _react2 = _interopRequireDefault(_react);

var _propTypes = __webpack_require__(25);

var _propTypes2 = _interopRequireDefault(_propTypes);

var _skylightstateless = __webpack_require__(208);

var _skylightstateless2 = _interopRequireDefault(_skylightstateless);

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 isOpening = function isOpening(s1, s2) {
  return !s1.isVisible && s2.isVisible;
};
var isClosing = function isClosing(s1, s2) {
  return s1.isVisible && !s2.isVisible;
};

var SkyLight = function (_React$Component) {
  _inherits(SkyLight, _React$Component);

  function SkyLight(props) {
    _classCallCheck(this, SkyLight);

    var _this = _possibleConstructorReturn(this, (SkyLight.__proto__ || Object.getPrototypeOf(SkyLight)).call(this, props));

    _this.state = { isVisible: false };
    return _this;
  }

  _createClass(SkyLight, [{
    key: 'componentWillUpdate',
    value: function componentWillUpdate(nextProps, nextState) {
      if (isOpening(this.state, nextState) && this.props.beforeOpen) {
        this.props.beforeOpen();
      }

      if (isClosing(this.state, nextState) && this.props.beforeClose) {
        this.props.beforeClose();
      }
    }
  }, {
    key: 'componentDidUpdate',
    value: function componentDidUpdate(prevProps, prevState) {
      if (isOpening(prevState, this.state) && this.props.afterOpen) {
        this.props.afterOpen();
      }

      if (isClosing(prevState, this.state) && this.props.afterClose) {
        this.props.afterClose();
      }
    }
  }, {
    key: 'show',
    value: function show() {
      this.setState({ isVisible: true });
    }
  }, {
    key: 'hide',
    value: function hide() {
      this.setState({ isVisible: false });
    }
  }, {
    key: '_onOverlayClicked',
    value: function _onOverlayClicked() {
      if (this.props.hideOnOverlayClicked) {
        this.hide();
      }

      if (this.props.onOverlayClicked) {
        this.props.onOverlayClicked();
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var _this2 = this;

      return _react2.default.createElement(_skylightstateless2.default, _extends({}, this.props, {
        isVisible: this.state.isVisible,
        onOverlayClicked: function onOverlayClicked() {
          return _this2._onOverlayClicked();
        },
        onCloseClicked: function onCloseClicked() {
          return _this2.hide();
        }
      }));
    }
  }]);

  return SkyLight;
}(_react2.default.Component);

exports.default = SkyLight;


SkyLight.displayName = 'SkyLight';

SkyLight.propTypes = _extends({}, _skylightstateless2.default.sharedPropTypes, {
  afterClose: _propTypes2.default.func,
  afterOpen: _propTypes2.default.func,
  beforeClose: _propTypes2.default.func,
  beforeOpen: _propTypes2.default.func,
  hideOnOverlayClicked: _propTypes2.default.bool
});

SkyLight.defaultProps = _extends({}, _skylightstateless2.default.defaultProps, {
  hideOnOverlayClicked: false
});

/***/ }),
/* 284 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

var styles = {
  overlayStyles: {
    position: 'fixed',
    top: '0px',
    left: '0px',
    width: '100%',
    height: '100%',
    zIndex: '99',
    backgroundColor: 'rgba(0,0,0,0.3)',
    transitionProperty: 'all',
    transitionTimingFunction: 'ease',
    display: 'none'
  },
  dialogStyles: {
    width: '50%',
    height: '400px',
    position: 'fixed',
    top: '50%',
    left: '50%',
    marginTop: '-200px',
    marginLeft: '-25%',
    backgroundColor: '#fff',
    borderRadius: '2px',
    zIndex: '100',
    padding: '15px',
    boxShadow: '0px 0px 4px rgba(0,0,0,.14),0px 4px 8px rgba(0,0,0,.28)'
  },
  animationBase: {
    transform: 'scale(0)',
    transitionProperty: 'transform',
    transitionTimingFunction: 'ease'
  },
  animationOpen: {
    transform: 'scale(1)',
    transitionProperty: 'transform',
    transitionTimingFunction: 'ease'
  },
  title: {
    marginTop: '0px'
  },
  closeButtonStyle: {
    cursor: 'pointer',
    position: 'absolute',
    fontSize: '1.8em',
    right: '10px',
    top: '0px'
  }
};

exports.default = styles;

/***/ }),
/* 285 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = function (target) {
  if (target === null) {
    throw new TypeError('Cannot convert undefined or null to object');
  }

  var newTarget = target;

  for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    args[_key - 1] = arguments[_key];
  }

  for (var index = 0; index < args.length; index++) {
    var source = args[index];
    if (source !== null) {
      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          newTarget[key] = source[key];
        }
      }
    }
  }
  return newTarget;
};

/***/ })
/******/ ]);