diff --git a/thirdparty/systemjs/.agignore b/thirdparty/systemjs/.agignore
new file mode 100644
index 000000000..a261f2917
--- /dev/null
+++ b/thirdparty/systemjs/.agignore
@@ -0,0 +1 @@
+dist/*
diff --git a/thirdparty/systemjs/.gitignore b/thirdparty/systemjs/.gitignore
new file mode 100644
index 000000000..76a84faec
--- /dev/null
+++ b/thirdparty/systemjs/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+bower_components
+.DS_Store
diff --git a/thirdparty/systemjs/.travis.yml b/thirdparty/systemjs/.travis.yml
new file mode 100644
index 000000000..b09421142
--- /dev/null
+++ b/thirdparty/systemjs/.travis.yml
@@ -0,0 +1,14 @@
+git:
+ depth: 1
+language: node_js
+node_js:
+ - '0.10'
+ - '0.12'
+ - '4'
+ - '6'
+
+before_install:
+ - npm install
+script:
+ - npm run build
+ - npm run test
diff --git a/thirdparty/systemjs/LICENSE b/thirdparty/systemjs/LICENSE
new file mode 100644
index 000000000..1e467a8cf
--- /dev/null
+++ b/thirdparty/systemjs/LICENSE
@@ -0,0 +1,10 @@
+MIT License
+-----------
+
+Copyright (C) 2013-2016 Guy Bedford
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/thirdparty/systemjs/Makefile b/thirdparty/systemjs/Makefile
new file mode 100755
index 000000000..cc002c540
--- /dev/null
+++ b/thirdparty/systemjs/Makefile
@@ -0,0 +1,186 @@
+VERSION = $(shell cat package.json | sed -n 's/.*"version": "\([^"]*\)",/\1/p')
+
+define BANNER
+/*
+ * SystemJS v$(VERSION)
+ */
+endef
+export BANNER
+
+define POLYFILLS_BANNER
+/*
+ * SystemJS Promise Polyfill
+ */
+endef
+export POLYFILLS_BANNER
+
+define STANDARD_VERSION
+
+System.version = '$(VERSION) Standard';
+endef
+export STANDARD_VERSION
+
+define REGISTER_VERSION
+
+System.version = '$(VERSION) Register Only';
+endef
+export REGISTER_VERSION
+
+define CSP_VERSION
+
+System.version = '$(VERSION) CSP';
+endef
+export CSP_VERSION
+
+compile: clean-compile dist/system.src.js dist/system.perf.js dist/system-csp-production.src.js dist/system-register-only.src.js
+build: clean dist/system.js dist/system-csp-production.js dist/system-register-only.js dist/system-polyfills.js
+
+version:
+ @echo $(VERSION)
+
+footprint: build
+ @cat dist/system.js | gzip -9f | wc -c
+ @cat dist/system-csp-production.js | gzip -9f | wc -c
+ @cat dist/system-register-only.js | gzip -9f | wc -c
+ @cat dist/system-polyfills.js | gzip -9f | wc -c
+
+clean-compile:
+ @rm -f dist/system.src.js dist/system.perf.js dist/system-csp-production.src.js
+
+clean:
+ @rm -f dist/*
+
+test: compile
+ open test/test-traceur.html test/test-traceur-runtime.html
+ sleep 0.1
+ open test/test-babel.html test/test-babel-runtime.html
+ sleep 0.1
+ open test/test-typescript.html
+ sleep 0.1
+ open test/test-csp.html test/test-tracer.html
+
+dist/system-polyfills.js: dist/system-polyfills.src.js
+ cd dist && ../node_modules/.bin/uglifyjs $(subst dist/,,$<) --compress drop_console --preamble "$$POLYFILLS_BANNER" --mangle --source-map system-polyfills.js.map >> $(subst dist/,,$@) || rm $(subst dist/,,$@)
+
+dist/%.js: dist/%.src.js
+ cd dist && ../node_modules/.bin/uglifyjs $(subst dist/,,$<) --compress drop_console --preamble "$$BANNER" --mangle --source-map $*.js.map >> $(subst dist/,,$@) || rm $(subst dist/,,$@)
+
+dist/system.src.js: lib/*.js
+ ( echo "$$BANNER"; \
+ cat \
+ lib/wrapper-start.js \
+ lib/url-polyfill.js \
+ lib/loader-wrapper-start.js \
+ lib/system-fetch.js \
+ lib/legacy-transpiler.js \
+ lib/proto.js \
+ lib/global-eval.js \
+ lib/core.js \
+ lib/package.js \
+ lib/scriptLoader.js \
+ lib/register.js \
+ lib/esm.js \
+ lib/global.js \
+ lib/global-helpers.js \
+ lib/cjs.js \
+ lib/cjs-helpers.js \
+ lib/amd-helpers.js \
+ lib/amd.js \
+ lib/plugins.js \
+ lib/conditionals.js \
+ lib/alias.js \
+ lib/meta.js \
+ lib/bundles.js \
+ lib/depCache.js \
+ lib/createSystem.js \
+ ; echo "$$STANDARD_VERSION" ; cat \
+ lib/loader-wrapper-end.js \
+ lib/wrapper-end.js \
+ ) > $@;
+
+dist/system.perf.js: lib/*.js
+ ( echo "$$BANNER"; \
+ cat \
+ lib/wrapper-start.js \
+ lib/url-polyfill.js \
+ lib/loader-wrapper-start.js \
+ lib/legacy-transpiler.js \
+ lib/proto.js \
+ lib/perf.js \
+ lib/global-eval.js \
+ lib/core.js \
+ lib/package.js \
+ lib/scriptLoader.js \
+ lib/register.js \
+ lib/esm.js \
+ lib/global.js \
+ lib/global-helpers.js \
+ lib/cjs.js \
+ lib/cjs-helpers.js \
+ lib/amd-helpers.js \
+ lib/amd.js \
+ lib/plugins.js \
+ lib/conditionals.js \
+ lib/alias.js \
+ lib/meta.js \
+ lib/bundles.js \
+ lib/depCache.js \
+ lib/createSystem.js \
+ ; echo "$$STANDARD_VERSION" ; cat \
+ lib/loader-wrapper-end.js \
+ lib/wrapper-end.js \
+ ) > $@;
+
+dist/system-csp-production.src.js: lib/*.js
+ ( echo "$$BANNER"; \
+ cat \
+ lib/wrapper-start.js \
+ lib/url-polyfill.js \
+ lib/loader-wrapper-start.js \
+ lib/proto.js \
+ lib/system-fetch.js \
+ lib/core.js \
+ lib/package.js \
+ lib/scriptLoader.js \
+ lib/register.js \
+ lib/global-helpers.js \
+ lib/cjs-helpers.js \
+ lib/amd-helpers.js \
+ lib/plugins.js \
+ lib/conditionals.js \
+ lib/alias.js \
+ lib/meta.js \
+ lib/bundles.js \
+ lib/depCache.js \
+ lib/scriptOnly.js \
+ lib/createSystem.js \
+ ; echo "$$CSP_VERSION" ; cat \
+ lib/loader-wrapper-end.js \
+ lib/wrapper-end.js \
+ ) > $@;
+
+dist/system-register-only.src.js: lib/*.js
+ ( echo "$$BANNER"; \
+ cat \
+ lib/url-polyfill.js \
+ lib/loader-wrapper-start.js \
+ lib/proto.js \
+ lib/system-only-resolve.js \
+ lib/scriptLoader.js \
+ lib/register.js \
+ lib/bundles.js \
+ lib/scriptOnly.js \
+ lib/createSystem.js \
+ ; echo "$$REGISTER_VERSION" ; cat \
+ lib/loader-wrapper-end.js \
+ ) > $@;
+
+dist/system-polyfills.src.js: lib/*.js
+ ( echo "$$POLYFILLS_BANNER"; \
+ echo "(function(define) {"; \
+ echo ""; \
+ cat \
+ node_modules/when/es6-shim/Promise.js \
+ lib/polyfills-bootstrap.js; \
+ echo "})();" \
+ ) > $@;
\ No newline at end of file
diff --git a/thirdparty/systemjs/README.md b/thirdparty/systemjs/README.md
new file mode 100644
index 000000000..afe998a27
--- /dev/null
+++ b/thirdparty/systemjs/README.md
@@ -0,0 +1,149 @@
+SystemJS
+========
+
+[![Build Status][travis-image]][travis-url]
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/systemjs/systemjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Support](https://supporterhq.com/api/b/33df4abbec4d39260f49015d2457eafe/SystemJS)](https://supporterhq.com/support/33df4abbec4d39260f49015d2457eafe/SystemJS)
+
+Universal dynamic module loader - loads ES6 modules, AMD, CommonJS and global scripts in the browser and NodeJS.
+
+* [Loads any module format](docs/module-formats.md) with [exact circular reference and binding support](https://github.com/ModuleLoader/es6-module-loader/blob/v0.17.0/docs/circular-references-bindings.md).
+* Loads [ES6 modules compiled into the `System.register` bundle format for production](docs/production-workflows.md), maintaining circular references support.
+* Supports RequireJS-style [map](docs/overview.md#map-config), [paths](https://github.com/ModuleLoader/es6-module-loader/blob/master/docs/loader-config.md#paths-implementation), [bundles](docs/production-workflows.md#bundle-extension) and [global shims](docs/module-formats.md#shim-dependencies).
+* [Loader plugins](docs/overview.md#plugin-loaders) allow custom transpilation or asset loading.
+
+Built to the format ES6-specified loader API from [ES6 Specification Draft Rev 27, Section 15](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#august_24_2014_draft_rev_27),
+and will be updated to the [WhatWG loader API](https://whatwg.github.io/loader/) as soon as it can be considered stable for implementation.
+
+~19KB minified and gzipped, runs in IE8+ and NodeJS.
+
+For discussion, join the [Gitter Room](https://gitter.im/systemjs/systemjs).
+
+Documentation
+---
+
+* [ES6 Modules Overview](docs/es6-modules-overview.md)
+* [SystemJS Overview](docs/overview.md)
+* [Config API](docs/config-api.md)
+* [Module Formats](docs/module-formats.md)
+* [Production Workflows](docs/production-workflows.md)
+* [System API](docs/system-api.md)
+* [Creating Plugins](docs/creating-plugins.md)
+
+Basic Use
+---
+
+### Browser
+
+```html
+
+
+```
+
+The above will support loading all module formats, including ES Modules transpiled into the System.register format.
+
+To load ES6 code with in-browser transpilation, configure one of the following transpiler plugins:
+
+* [Babel](https://github.com/systemjs/plugin-babel)
+* [TypeScript](https://github.com/frankwallis/plugin-typescript)
+* [Traceur](http://github.com/systemjs/plugin-traceur)
+
+### Promise Polyfill
+
+SystemJS relies on `Promise` being present in the environment.
+
+For the best performance in IE and older browsers, it is advisable to load a polyfill like [Bluebird](https://github.com/petkaantonov/bluebird) or [es6-promise](https://github.com/stefanpenner/es6-promise) before SystemJS.
+
+Otherwise, when Promise is not available, SystemJS will attempt to load the `system-polyfills.js` file located in the dist folder which contains the when.js Promise polyfill.
+
+### NodeJS
+
+To load modules in NodeJS, install SystemJS with:
+
+```
+ npm install systemjs
+```
+
+If transpiling ES6, also install the transpiler plugin, following the instructions from the transpiler project page.
+
+We can then load modules equivalently in NodeJS as we do in the browser:
+
+```javascript
+var SystemJS = require('systemjs');
+
+// loads './app.js' from the current directory
+SystemJS.import('./app.js').then(function(m) {
+ console.log(m);
+});
+```
+
+If you are using jspm as a package manager you will also need to load the generated configuration.
+The best way to do this in node is to get your `System` instance through jspm, which will automatically load your config correctly for you:
+
+```js
+var Loader = require('jspm').Loader;
+var SystemJS = new Loader();
+
+SystemJS.import('lodash').then(function (_) {
+ console.log(_);
+});
+```
+
+### Plugins
+
+Supported loader plugins:
+
+* [CSS](https://github.com/systemjs/plugin-css)
+* [LESS](https://github.com/systemjs/plugin-less)
+* [Image](https://github.com/systemjs/plugin-image)
+* [JSON](https://github.com/systemjs/plugin-json)
+* [Text](https://github.com/systemjs/plugin-text)
+* [Node Binary](https://github.com/systemjs/plugin-node-binary)
+
+Additional Plugins:
+
+* [Audio](https://github.com/ozsay/plugin-audio)
+* [CoffeeScript](https://github.com/forresto/plugin-coffee)
+* [Ember Handlebars](https://github.com/n-fuse/plugin-ember-hbs)
+* [Handlebars](https://github.com/davis/plugin-hbs)
+* [HTML](https://github.com/Hypercubed/systemjs-plugin-html/)
+* [Image (lazy)](https://github.com/laurentgoudet/plugin-lazyimage)
+* [Jade](https://github.com/johnsoftek/plugin-jade)
+* [Jade VirtualDOM](https://github.com/WorldMaker/system-jade-virtualdom)
+* [jst](https://github.com/podio/plugin-jst)
+* [JSX](https://github.com/floatdrop/plugin-jsx)
+* [Markdown](https://github.com/guybedford/plugin-md)
+* [raw](https://github.com/matthewbauer/plugin-raw)
+* [SASS](https://github.com/screendriver/plugin-sass)
+* [SCSS](https://github.com/kevcjones/plugin-scss)
+* [sofe](https://github.com/CanopyTax/sofe)
+* [SVG](https://github.com/vuzonp/systemjs-plugin-svg)
+* [WebFont](https://github.com/guybedford/plugin-font)
+* [WebWorkers](https://github.com/casperlamboo/plugin-worker)
+* [YAML](https://github.com/tb/plugin-yaml)
+
+Guides:
+
+* [Using plugins](docs/overview.md#plugin-loaders)
+* [Creating plugins](docs/creating-plugins.md)
+
+#### Running the tests
+
+To install the dependencies correctly, run `bower install` from the root of the repo, then open `test/test.html` in a browser with a local server
+or file access flags enabled.
+
+License
+---
+
+MIT
+
+[travis-url]: https://travis-ci.org/systemjs/systemjs
+[travis-image]: https://travis-ci.org/systemjs/systemjs.svg?branch=master
diff --git a/thirdparty/systemjs/bench/cjs-sample/cjs.js b/thirdparty/systemjs/bench/cjs-sample/cjs.js
new file mode 100644
index 000000000..376672579
--- /dev/null
+++ b/thirdparty/systemjs/bench/cjs-sample/cjs.js
@@ -0,0 +1,949 @@
+/**
+ * Copyright 2013-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMComponent
+ */
+
+/* global hasOwnProperty:true */
+
+'use strict';
+
+var _assign = require('object-assign');
+
+var AutoFocusUtils = require('./AutoFocusUtils');
+var CSSPropertyOperations = require('./CSSPropertyOperations');
+var DOMLazyTree = require('./DOMLazyTree');
+var DOMNamespaces = require('./DOMNamespaces');
+var DOMProperty = require('./DOMProperty');
+var DOMPropertyOperations = require('./DOMPropertyOperations');
+var EventConstants = require('./EventConstants');
+var EventPluginHub = require('./EventPluginHub');
+var EventPluginRegistry = require('./EventPluginRegistry');
+var ReactBrowserEventEmitter = require('./ReactBrowserEventEmitter');
+var ReactComponentBrowserEnvironment = require('./ReactComponentBrowserEnvironment');
+var ReactDOMButton = require('./ReactDOMButton');
+var ReactDOMComponentFlags = require('./ReactDOMComponentFlags');
+var ReactDOMComponentTree = require('./ReactDOMComponentTree');
+var ReactDOMInput = require('./ReactDOMInput');
+var ReactDOMOption = require('./ReactDOMOption');
+var ReactDOMSelect = require('./ReactDOMSelect');
+var ReactDOMTextarea = require('./ReactDOMTextarea');
+var ReactInstrumentation = require('./ReactInstrumentation');
+var ReactMultiChild = require('./ReactMultiChild');
+var ReactServerRenderingTransaction = require('./ReactServerRenderingTransaction');
+
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var escapeTextContentForBrowser = require('./escapeTextContentForBrowser');
+var invariant = require('fbjs/lib/invariant');
+var isEventSupported = require('./isEventSupported');
+var keyOf = require('fbjs/lib/keyOf');
+var shallowEqual = require('fbjs/lib/shallowEqual');
+var validateDOMNesting = require('./validateDOMNesting');
+var warning = require('fbjs/lib/warning');
+
+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 = keyOf({ style: null });
+var HTML = keyOf({ __html: null });
+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;
+
+ process.env.NODE_ENV !== 'production' ? 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) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s is a void element tag and must not have `children` or ' + 'use `props.dangerouslySetInnerHTML`.%s', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : invariant(false) : void 0;
+ }
+ if (props.dangerouslySetInnerHTML != null) {
+ !(props.children == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : void 0;
+ !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? process.env.NODE_ENV !== 'production' ? invariant(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' + 'for more information.') : invariant(false) : void 0;
+ }
+ if (process.env.NODE_ENV !== 'production') {
+ process.env.NODE_ENV !== 'production' ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : void 0;
+ process.env.NODE_ENV !== 'production' ? 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;
+ process.env.NODE_ENV !== 'production' ? 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') ? process.env.NODE_ENV !== 'production' ? 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)) : invariant(false) : void 0;
+}
+
+function enqueuePutListener(inst, registrationName, listener, transaction) {
+ if (transaction instanceof ReactServerRenderingTransaction) {
+ return;
+ }
+ if (process.env.NODE_ENV !== 'production') {
+ // IE8 has no API for event capturing and the `onScroll` event doesn't
+ // bubble.
+ process.env.NODE_ENV !== 'production' ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), 'This browser doesn\'t support the `onScroll` event') : void 0;
+ }
+ var containerInfo = inst._nativeContainerInfo;
+ 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 optionPostMount() {
+ var inst = this;
+ ReactDOMOption.postMountWrapper(inst);
+}
+
+var setContentChildForInstrumentation = emptyFunction;
+if (process.env.NODE_ENV !== 'production') {
+ setContentChildForInstrumentation = function (contentToUse) {
+ var debugID = this._debugID;
+ var contentDebugID = debugID + '#text';
+ this._contentDebugID = contentDebugID;
+ ReactInstrumentation.debugTool.onSetDisplayName(contentDebugID, '#text');
+ ReactInstrumentation.debugTool.onSetText(contentDebugID, '' + contentToUse);
+ 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 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 ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Must be mounted to trap events') : invariant(false) : void 0;
+ var node = getNode(inst);
+ !node ? process.env.NODE_ENV !== 'production' ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : invariant(false) : void 0;
+
+ switch (inst._tag) {
+ case 'iframe':
+ case 'object':
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.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(EventConstants.topLevelTypes[event], mediaEvents[event], node));
+ }
+ }
+
+ break;
+ case 'img':
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error', node), ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load', node)];
+ break;
+ case 'form':
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset', node), ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit', node)];
+ break;
+ case 'input':
+ case 'select':
+ case 'textarea':
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.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) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Invalid tag: %s', tag) : invariant(false) : 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._nativeNode = null;
+ this._nativeParent = null;
+ this._rootNodeID = null;
+ this._domID = null;
+ this._nativeContainerInfo = null;
+ this._wrapperState = null;
+ this._topLevelWrapper = null;
+ this._flags = 0;
+ if (process.env.NODE_ENV !== 'production') {
+ this._ancestorInfo = null;
+ this._contentDebugID = 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 containing DOM component instance
+ * @param {?object} info about the native container
+ * @param {object} context
+ * @return {string} The computed markup.
+ */
+ mountComponent: function (transaction, nativeParent, nativeContainerInfo, context) {
+ this._rootNodeID = globalIdCounter++;
+ this._domID = nativeContainerInfo._idCounter++;
+ this._nativeParent = nativeParent;
+ this._nativeContainerInfo = nativeContainerInfo;
+
+ var props = this._currentElement.props;
+
+ switch (this._tag) {
+ case 'iframe':
+ case 'object':
+ case 'img':
+ case 'form':
+ case 'video':
+ case 'audio':
+ this._wrapperState = {
+ listeners: null
+ };
+ transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
+ break;
+ case 'button':
+ props = ReactDOMButton.getNativeProps(this, props, nativeParent);
+ break;
+ case 'input':
+ ReactDOMInput.mountWrapper(this, props, nativeParent);
+ props = ReactDOMInput.getNativeProps(this, props);
+ transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
+ break;
+ case 'option':
+ ReactDOMOption.mountWrapper(this, props, nativeParent);
+ props = ReactDOMOption.getNativeProps(this, props);
+ break;
+ case 'select':
+ ReactDOMSelect.mountWrapper(this, props, nativeParent);
+ props = ReactDOMSelect.getNativeProps(this, props);
+ transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
+ break;
+ case 'textarea':
+ ReactDOMTextarea.mountWrapper(this, props, nativeParent);
+ props = ReactDOMTextarea.getNativeProps(this, props);
+ 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 (nativeParent != null) {
+ namespaceURI = nativeParent._namespaceURI;
+ parentTag = nativeParent._tag;
+ } else if (nativeContainerInfo._tag) {
+ namespaceURI = nativeContainerInfo._namespaceURI;
+ parentTag = nativeContainerInfo._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 (process.env.NODE_ENV !== 'production') {
+ var parentInfo;
+ if (nativeParent != null) {
+ parentInfo = nativeParent._ancestorInfo;
+ } else if (nativeContainerInfo._tag) {
+ parentInfo = nativeContainerInfo._ancestorInfo;
+ }
+ if (parentInfo) {
+ // parentInfo should always be present except for the top-level
+ // component when server rendering
+ validateDOMNesting(this._tag, this, parentInfo);
+ }
+ this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
+ }
+
+ var mountImage;
+ if (transaction.useCreateElement) {
+ var ownerDocument = nativeContainerInfo._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 {
+ el = ownerDocument.createElement(this._currentElement.type, props.is || null);
+ }
+ } else {
+ el = ownerDocument.createElementNS(namespaceURI, this._currentElement.type);
+ }
+ ReactDOMComponentTree.precacheNode(this, el);
+ this._flags |= Flags.hasCachedChildNodes;
+ if (!this._nativeParent) {
+ 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 'button':
+ case 'input':
+ case 'select':
+ case 'textarea':
+ if (props.autoFocus) {
+ transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
+ }
+ break;
+ case 'option':
+ transaction.getReactMountReady().enqueue(optionPostMount, this);
+ }
+
+ 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 (process.env.NODE_ENV !== 'production') {
+ // 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._nativeParent) {
+ 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 (process.env.NODE_ENV !== 'production') {
+ setContentChildForInstrumentation.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:
+ // See:
+ // See:
+ // See: Parsing of "textarea" "listing" and "pre" elements
+ // from
+ 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;
+ if (contentToUse != null) {
+ // TODO: Validate that text is allowed as a child of this node
+ if (process.env.NODE_ENV !== 'production') {
+ setContentChildForInstrumentation.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 native 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 'button':
+ lastProps = ReactDOMButton.getNativeProps(this, lastProps);
+ nextProps = ReactDOMButton.getNativeProps(this, nextProps);
+ break;
+ case 'input':
+ ReactDOMInput.updateWrapper(this);
+ lastProps = ReactDOMInput.getNativeProps(this, lastProps);
+ nextProps = ReactDOMInput.getNativeProps(this, nextProps);
+ break;
+ case 'option':
+ lastProps = ReactDOMOption.getNativeProps(this, lastProps);
+ nextProps = ReactDOMOption.getNativeProps(this, nextProps);
+ break;
+ case 'select':
+ lastProps = ReactDOMSelect.getNativeProps(this, lastProps);
+ nextProps = ReactDOMSelect.getNativeProps(this, nextProps);
+ break;
+ case 'textarea':
+ ReactDOMTextarea.updateWrapper(this);
+ lastProps = ReactDOMTextarea.getNativeProps(this, lastProps);
+ nextProps = ReactDOMTextarea.getNativeProps(this, nextProps);
+ break;
+ }
+
+ assertValidProps(this, nextProps);
+ this._updateDOMProperties(lastProps, nextProps, transaction);
+ this._updateDOMChildren(lastProps, nextProps, transaction, context);
+
+ if (this._tag === 'select') {
+ //